18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*******************************************************************************
38c2ecf20Sopenharmony_ci * IBM Virtual SCSI Target Driver
48c2ecf20Sopenharmony_ci * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
58c2ecf20Sopenharmony_ci *			   Santiago Leon (santil@us.ibm.com) IBM Corp.
68c2ecf20Sopenharmony_ci *			   Linda Xie (lxie@us.ibm.com) IBM Corp.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
98c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
128c2ecf20Sopenharmony_ci * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.com>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci ****************************************************************************/
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/types.h>
228c2ecf20Sopenharmony_ci#include <linux/list.h>
238c2ecf20Sopenharmony_ci#include <linux/string.h>
248c2ecf20Sopenharmony_ci#include <linux/delay.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <target/target_core_base.h>
278c2ecf20Sopenharmony_ci#include <target/target_core_fabric.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <asm/hvcall.h>
308c2ecf20Sopenharmony_ci#include <asm/vio.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <scsi/viosrp.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "ibmvscsi_tgt.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define IBMVSCSIS_VERSION	"v0.2"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define	INITIAL_SRP_LIMIT	1024
398c2ecf20Sopenharmony_ci#define	DEFAULT_MAX_SECTORS	256
408c2ecf20Sopenharmony_ci#define MAX_TXU			1024 * 1024
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic uint max_vdma_size = MAX_H_COPY_RDMA;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic char system_id[SYS_ID_NAME_LEN] = "";
458c2ecf20Sopenharmony_cistatic char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
468c2ecf20Sopenharmony_cistatic uint partition_number = -1;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* Adapter list and lock to control it */
498c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ibmvscsis_dev_lock);
508c2ecf20Sopenharmony_cistatic LIST_HEAD(ibmvscsis_dev_list);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic long ibmvscsis_parse_command(struct scsi_info *vscsi,
538c2ecf20Sopenharmony_ci				    struct viosrp_crq *crq);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void ibmvscsis_adapter_idle(struct scsi_info *vscsi);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
588c2ecf20Sopenharmony_ci				      struct srp_rsp *rsp)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	u32 residual_count = se_cmd->residual_count;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (!residual_count)
638c2ecf20Sopenharmony_ci		return;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
668c2ecf20Sopenharmony_ci		if (se_cmd->data_direction == DMA_TO_DEVICE) {
678c2ecf20Sopenharmony_ci			/* residual data from an underflow write */
688c2ecf20Sopenharmony_ci			rsp->flags = SRP_RSP_FLAG_DOUNDER;
698c2ecf20Sopenharmony_ci			rsp->data_out_res_cnt = cpu_to_be32(residual_count);
708c2ecf20Sopenharmony_ci		} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
718c2ecf20Sopenharmony_ci			/* residual data from an underflow read */
728c2ecf20Sopenharmony_ci			rsp->flags = SRP_RSP_FLAG_DIUNDER;
738c2ecf20Sopenharmony_ci			rsp->data_in_res_cnt = cpu_to_be32(residual_count);
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	} else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
768c2ecf20Sopenharmony_ci		if (se_cmd->data_direction == DMA_TO_DEVICE) {
778c2ecf20Sopenharmony_ci			/* residual data from an overflow write */
788c2ecf20Sopenharmony_ci			rsp->flags = SRP_RSP_FLAG_DOOVER;
798c2ecf20Sopenharmony_ci			rsp->data_out_res_cnt = cpu_to_be32(residual_count);
808c2ecf20Sopenharmony_ci		} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
818c2ecf20Sopenharmony_ci			/* residual data from an overflow read */
828c2ecf20Sopenharmony_ci			rsp->flags = SRP_RSP_FLAG_DIOVER;
838c2ecf20Sopenharmony_ci			rsp->data_in_res_cnt = cpu_to_be32(residual_count);
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/**
898c2ecf20Sopenharmony_ci * connection_broken() - Determine if the connection to the client is good
908c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * This function attempts to send a ping MAD to the client. If the call to
938c2ecf20Sopenharmony_ci * queue the request returns H_CLOSED then the connection has been broken
948c2ecf20Sopenharmony_ci * and the function returns TRUE.
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
978c2ecf20Sopenharmony_ci *	Interrupt or Process environment
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_cistatic bool connection_broken(struct scsi_info *vscsi)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
1028c2ecf20Sopenharmony_ci	u64 buffer[2] = { 0, 0 };
1038c2ecf20Sopenharmony_ci	long h_return_code;
1048c2ecf20Sopenharmony_ci	bool rc = false;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* create a PING crq */
1078c2ecf20Sopenharmony_ci	crq = (struct viosrp_crq *)&buffer;
1088c2ecf20Sopenharmony_ci	crq->valid = VALID_CMD_RESP_EL;
1098c2ecf20Sopenharmony_ci	crq->format = MESSAGE_IN_CRQ;
1108c2ecf20Sopenharmony_ci	crq->status = PING;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	h_return_code = h_send_crq(vscsi->dds.unit_id,
1138c2ecf20Sopenharmony_ci				   cpu_to_be64(buffer[MSG_HI]),
1148c2ecf20Sopenharmony_ci				   cpu_to_be64(buffer[MSG_LOW]));
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Connection_broken: rc %ld\n", h_return_code);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (h_return_code == H_CLOSED)
1198c2ecf20Sopenharmony_ci		rc = true;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return rc;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/**
1258c2ecf20Sopenharmony_ci * ibmvscsis_unregister_command_q() - Helper Function-Unregister Command Queue
1268c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * This function calls h_free_q then frees the interrupt bit etc.
1298c2ecf20Sopenharmony_ci * It must release the lock before doing so because of the time it can take
1308c2ecf20Sopenharmony_ci * for h_free_crq in PHYP
1318c2ecf20Sopenharmony_ci * NOTE: the caller must make sure that state and or flags will prevent
1328c2ecf20Sopenharmony_ci *	 interrupt handler from scheduling work.
1338c2ecf20Sopenharmony_ci * NOTE: anyone calling this function may need to set the CRQ_CLOSED flag
1348c2ecf20Sopenharmony_ci *	 we can't do it here, because we don't have the lock
1358c2ecf20Sopenharmony_ci *
1368c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
1378c2ecf20Sopenharmony_ci *	Process level
1388c2ecf20Sopenharmony_ci */
1398c2ecf20Sopenharmony_cistatic long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	long qrc;
1428c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
1438c2ecf20Sopenharmony_ci	int ticks = 0;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	do {
1468c2ecf20Sopenharmony_ci		qrc = h_free_crq(vscsi->dds.unit_id);
1478c2ecf20Sopenharmony_ci		switch (qrc) {
1488c2ecf20Sopenharmony_ci		case H_SUCCESS:
1498c2ecf20Sopenharmony_ci			spin_lock_bh(&vscsi->intr_lock);
1508c2ecf20Sopenharmony_ci			vscsi->flags &= ~PREP_FOR_SUSPEND_FLAGS;
1518c2ecf20Sopenharmony_ci			spin_unlock_bh(&vscsi->intr_lock);
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		case H_HARDWARE:
1558c2ecf20Sopenharmony_ci		case H_PARAMETER:
1568c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "unregister_command_q: error from h_free_crq %ld\n",
1578c2ecf20Sopenharmony_ci				qrc);
1588c2ecf20Sopenharmony_ci			rc = ERROR;
1598c2ecf20Sopenharmony_ci			break;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		case H_BUSY:
1628c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_1_MSEC:
1638c2ecf20Sopenharmony_ci			/* msleep not good for small values */
1648c2ecf20Sopenharmony_ci			usleep_range(1000, 2000);
1658c2ecf20Sopenharmony_ci			ticks += 1;
1668c2ecf20Sopenharmony_ci			break;
1678c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_10_MSEC:
1688c2ecf20Sopenharmony_ci			usleep_range(10000, 20000);
1698c2ecf20Sopenharmony_ci			ticks += 10;
1708c2ecf20Sopenharmony_ci			break;
1718c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_100_MSEC:
1728c2ecf20Sopenharmony_ci			msleep(100);
1738c2ecf20Sopenharmony_ci			ticks += 100;
1748c2ecf20Sopenharmony_ci			break;
1758c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_1_SEC:
1768c2ecf20Sopenharmony_ci			ssleep(1);
1778c2ecf20Sopenharmony_ci			ticks += 1000;
1788c2ecf20Sopenharmony_ci			break;
1798c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_10_SEC:
1808c2ecf20Sopenharmony_ci			ssleep(10);
1818c2ecf20Sopenharmony_ci			ticks += 10000;
1828c2ecf20Sopenharmony_ci			break;
1838c2ecf20Sopenharmony_ci		case H_LONG_BUSY_ORDER_100_SEC:
1848c2ecf20Sopenharmony_ci			ssleep(100);
1858c2ecf20Sopenharmony_ci			ticks += 100000;
1868c2ecf20Sopenharmony_ci			break;
1878c2ecf20Sopenharmony_ci		default:
1888c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "unregister_command_q: unknown error %ld from h_free_crq\n",
1898c2ecf20Sopenharmony_ci				qrc);
1908c2ecf20Sopenharmony_ci			rc = ERROR;
1918c2ecf20Sopenharmony_ci			break;
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		/*
1958c2ecf20Sopenharmony_ci		 * dont wait more then 300 seconds
1968c2ecf20Sopenharmony_ci		 * ticks are in milliseconds more or less
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		if (ticks > 300000 && qrc != H_SUCCESS) {
1998c2ecf20Sopenharmony_ci			rc = ERROR;
2008c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "Excessive wait for h_free_crq\n");
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci	} while (qrc != H_SUCCESS && rc == ADAPT_SUCCESS);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Freeing CRQ: phyp rc %ld, rc %ld\n", qrc, rc);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return rc;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/**
2108c2ecf20Sopenharmony_ci * ibmvscsis_delete_client_info() - Helper function to Delete Client Info
2118c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
2128c2ecf20Sopenharmony_ci * @client_closed:	True if client closed its queue
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Deletes information specific to the client when the client goes away
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
2178c2ecf20Sopenharmony_ci *	Interrupt or Process
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_cistatic void ibmvscsis_delete_client_info(struct scsi_info *vscsi,
2208c2ecf20Sopenharmony_ci					 bool client_closed)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	vscsi->client_cap = 0;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/*
2258c2ecf20Sopenharmony_ci	 * Some things we don't want to clear if we're closing the queue,
2268c2ecf20Sopenharmony_ci	 * because some clients don't resend the host handshake when they
2278c2ecf20Sopenharmony_ci	 * get a transport event.
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	if (client_closed)
2308c2ecf20Sopenharmony_ci		vscsi->client_data.os_type = 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/**
2348c2ecf20Sopenharmony_ci * ibmvscsis_free_command_q() - Free Command Queue
2358c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
2368c2ecf20Sopenharmony_ci *
2378c2ecf20Sopenharmony_ci * This function calls unregister_command_q, then clears interrupts and
2388c2ecf20Sopenharmony_ci * any pending interrupt acknowledgments associated with the command q.
2398c2ecf20Sopenharmony_ci * It also clears memory if there is no error.
2408c2ecf20Sopenharmony_ci *
2418c2ecf20Sopenharmony_ci * PHYP did not meet the PAPR architecture so that we must give up the
2428c2ecf20Sopenharmony_ci * lock. This causes a timing hole regarding state change.  To close the
2438c2ecf20Sopenharmony_ci * hole this routine does accounting on any change that occurred during
2448c2ecf20Sopenharmony_ci * the time the lock is not held.
2458c2ecf20Sopenharmony_ci * NOTE: must give up and then acquire the interrupt lock, the caller must
2468c2ecf20Sopenharmony_ci *	 make sure that state and or flags will prevent interrupt handler from
2478c2ecf20Sopenharmony_ci *	 scheduling work.
2488c2ecf20Sopenharmony_ci *
2498c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
2508c2ecf20Sopenharmony_ci *	Process level, interrupt lock is held
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_cistatic long ibmvscsis_free_command_q(struct scsi_info *vscsi)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	int bytes;
2558c2ecf20Sopenharmony_ci	u32 flags_under_lock;
2568c2ecf20Sopenharmony_ci	u16 state_under_lock;
2578c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (!(vscsi->flags & CRQ_CLOSED)) {
2608c2ecf20Sopenharmony_ci		vio_disable_interrupts(vscsi->dma_dev);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		state_under_lock = vscsi->new_state;
2638c2ecf20Sopenharmony_ci		flags_under_lock = vscsi->flags;
2648c2ecf20Sopenharmony_ci		vscsi->phyp_acr_state = 0;
2658c2ecf20Sopenharmony_ci		vscsi->phyp_acr_flags = 0;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
2688c2ecf20Sopenharmony_ci		rc = ibmvscsis_unregister_command_q(vscsi);
2698c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci		if (state_under_lock != vscsi->new_state)
2728c2ecf20Sopenharmony_ci			vscsi->phyp_acr_state = vscsi->new_state;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		vscsi->phyp_acr_flags = ((~flags_under_lock) & vscsi->flags);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		if (rc == ADAPT_SUCCESS) {
2778c2ecf20Sopenharmony_ci			bytes = vscsi->cmd_q.size * PAGE_SIZE;
2788c2ecf20Sopenharmony_ci			memset(vscsi->cmd_q.base_addr, 0, bytes);
2798c2ecf20Sopenharmony_ci			vscsi->cmd_q.index = 0;
2808c2ecf20Sopenharmony_ci			vscsi->flags |= CRQ_CLOSED;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			ibmvscsis_delete_client_info(vscsi, false);
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "free_command_q: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
2868c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
2878c2ecf20Sopenharmony_ci			vscsi->phyp_acr_state);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	return rc;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/**
2938c2ecf20Sopenharmony_ci * ibmvscsis_cmd_q_dequeue() - Get valid Command element
2948c2ecf20Sopenharmony_ci * @mask:	Mask to use in case index wraps
2958c2ecf20Sopenharmony_ci * @current_index:	Current index into command queue
2968c2ecf20Sopenharmony_ci * @base_addr:	Pointer to start of command queue
2978c2ecf20Sopenharmony_ci *
2988c2ecf20Sopenharmony_ci * Returns a pointer to a valid command element or NULL, if the command
2998c2ecf20Sopenharmony_ci * queue is empty
3008c2ecf20Sopenharmony_ci *
3018c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
3028c2ecf20Sopenharmony_ci *	Interrupt environment, interrupt lock held
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistatic struct viosrp_crq *ibmvscsis_cmd_q_dequeue(uint mask,
3058c2ecf20Sopenharmony_ci						  uint *current_index,
3068c2ecf20Sopenharmony_ci						  struct viosrp_crq *base_addr)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct viosrp_crq *ptr;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	ptr = base_addr + *current_index;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (ptr->valid) {
3138c2ecf20Sopenharmony_ci		*current_index = (*current_index + 1) & mask;
3148c2ecf20Sopenharmony_ci		dma_rmb();
3158c2ecf20Sopenharmony_ci	} else {
3168c2ecf20Sopenharmony_ci		ptr = NULL;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return ptr;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/**
3238c2ecf20Sopenharmony_ci * ibmvscsis_send_init_message() - send initialize message to the client
3248c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
3258c2ecf20Sopenharmony_ci * @format:	Which Init Message format to send
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
3288c2ecf20Sopenharmony_ci *	Interrupt environment interrupt lock held
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic long ibmvscsis_send_init_message(struct scsi_info *vscsi, u8 format)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
3338c2ecf20Sopenharmony_ci	u64 buffer[2] = { 0, 0 };
3348c2ecf20Sopenharmony_ci	long rc;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	crq = (struct viosrp_crq *)&buffer;
3378c2ecf20Sopenharmony_ci	crq->valid = VALID_INIT_MSG;
3388c2ecf20Sopenharmony_ci	crq->format = format;
3398c2ecf20Sopenharmony_ci	rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
3408c2ecf20Sopenharmony_ci			cpu_to_be64(buffer[MSG_LOW]));
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return rc;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci/**
3468c2ecf20Sopenharmony_ci * ibmvscsis_check_init_msg() - Check init message valid
3478c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
3488c2ecf20Sopenharmony_ci * @format:	Pointer to return format of Init Message, if any.
3498c2ecf20Sopenharmony_ci *		Set to UNUSED_FORMAT if no Init Message in queue.
3508c2ecf20Sopenharmony_ci *
3518c2ecf20Sopenharmony_ci * Checks if an initialize message was queued by the initiatior
3528c2ecf20Sopenharmony_ci * after the queue was created and before the interrupt was enabled.
3538c2ecf20Sopenharmony_ci *
3548c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
3558c2ecf20Sopenharmony_ci *	Process level only, interrupt lock held
3568c2ecf20Sopenharmony_ci */
3578c2ecf20Sopenharmony_cistatic long ibmvscsis_check_init_msg(struct scsi_info *vscsi, uint *format)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
3608c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask, &vscsi->cmd_q.index,
3638c2ecf20Sopenharmony_ci				      vscsi->cmd_q.base_addr);
3648c2ecf20Sopenharmony_ci	if (!crq) {
3658c2ecf20Sopenharmony_ci		*format = (uint)UNUSED_FORMAT;
3668c2ecf20Sopenharmony_ci	} else if (crq->valid == VALID_INIT_MSG && crq->format == INIT_MSG) {
3678c2ecf20Sopenharmony_ci		*format = (uint)INIT_MSG;
3688c2ecf20Sopenharmony_ci		crq->valid = INVALIDATE_CMD_RESP_EL;
3698c2ecf20Sopenharmony_ci		dma_rmb();
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		/*
3728c2ecf20Sopenharmony_ci		 * the caller has ensured no initialize message was
3738c2ecf20Sopenharmony_ci		 * sent after the queue was
3748c2ecf20Sopenharmony_ci		 * created so there should be no other message on the queue.
3758c2ecf20Sopenharmony_ci		 */
3768c2ecf20Sopenharmony_ci		crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask,
3778c2ecf20Sopenharmony_ci					      &vscsi->cmd_q.index,
3788c2ecf20Sopenharmony_ci					      vscsi->cmd_q.base_addr);
3798c2ecf20Sopenharmony_ci		if (crq) {
3808c2ecf20Sopenharmony_ci			*format = (uint)(crq->format);
3818c2ecf20Sopenharmony_ci			rc = ERROR;
3828c2ecf20Sopenharmony_ci			crq->valid = INVALIDATE_CMD_RESP_EL;
3838c2ecf20Sopenharmony_ci			dma_rmb();
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci	} else {
3868c2ecf20Sopenharmony_ci		*format = (uint)(crq->format);
3878c2ecf20Sopenharmony_ci		rc = ERROR;
3888c2ecf20Sopenharmony_ci		crq->valid = INVALIDATE_CMD_RESP_EL;
3898c2ecf20Sopenharmony_ci		dma_rmb();
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return rc;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/**
3968c2ecf20Sopenharmony_ci * ibmvscsis_disconnect() - Helper function to disconnect
3978c2ecf20Sopenharmony_ci * @work:	Pointer to work_struct, gives access to our adapter structure
3988c2ecf20Sopenharmony_ci *
3998c2ecf20Sopenharmony_ci * An error has occurred or the driver received a Transport event,
4008c2ecf20Sopenharmony_ci * and the driver is requesting that the command queue be de-registered
4018c2ecf20Sopenharmony_ci * in a safe manner. If there is no outstanding I/O then we can stop the
4028c2ecf20Sopenharmony_ci * queue. If we are restarting the queue it will be reflected in the
4038c2ecf20Sopenharmony_ci * the state of the adapter.
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
4068c2ecf20Sopenharmony_ci *	Process environment
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistatic void ibmvscsis_disconnect(struct work_struct *work)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(work, struct scsi_info,
4118c2ecf20Sopenharmony_ci					       proc_work);
4128c2ecf20Sopenharmony_ci	u16 new_state;
4138c2ecf20Sopenharmony_ci	bool wait_idle = false;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
4168c2ecf20Sopenharmony_ci	new_state = vscsi->new_state;
4178c2ecf20Sopenharmony_ci	vscsi->new_state = 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	vscsi->flags |= DISCONNECT_SCHEDULED;
4208c2ecf20Sopenharmony_ci	vscsi->flags &= ~SCHEDULE_DISCONNECT;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "disconnect: flags 0x%x, state 0x%hx\n",
4238c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * check which state we are in and see if we
4278c2ecf20Sopenharmony_ci	 * should transitition to the new state
4288c2ecf20Sopenharmony_ci	 */
4298c2ecf20Sopenharmony_ci	switch (vscsi->state) {
4308c2ecf20Sopenharmony_ci	/* Should never be called while in this state. */
4318c2ecf20Sopenharmony_ci	case NO_QUEUE:
4328c2ecf20Sopenharmony_ci	/*
4338c2ecf20Sopenharmony_ci	 * Can never transition from this state;
4348c2ecf20Sopenharmony_ci	 * igonore errors and logout.
4358c2ecf20Sopenharmony_ci	 */
4368c2ecf20Sopenharmony_ci	case UNCONFIGURING:
4378c2ecf20Sopenharmony_ci		break;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* can transition from this state to UNCONFIGURING */
4408c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
4418c2ecf20Sopenharmony_ci		if (new_state == UNCONFIGURING)
4428c2ecf20Sopenharmony_ci			vscsi->state = new_state;
4438c2ecf20Sopenharmony_ci		break;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/*
4468c2ecf20Sopenharmony_ci	 * Can transition from this state to to unconfiguring
4478c2ecf20Sopenharmony_ci	 * or err disconnect.
4488c2ecf20Sopenharmony_ci	 */
4498c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
4508c2ecf20Sopenharmony_ci		switch (new_state) {
4518c2ecf20Sopenharmony_ci		case UNCONFIGURING:
4528c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
4538c2ecf20Sopenharmony_ci			vscsi->state = new_state;
4548c2ecf20Sopenharmony_ci			break;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		case WAIT_IDLE:
4578c2ecf20Sopenharmony_ci			break;
4588c2ecf20Sopenharmony_ci		default:
4598c2ecf20Sopenharmony_ci			break;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* can transition from this state to UNCONFIGURING */
4648c2ecf20Sopenharmony_ci	case ERR_DISCONNECTED:
4658c2ecf20Sopenharmony_ci		if (new_state == UNCONFIGURING)
4668c2ecf20Sopenharmony_ci			vscsi->state = new_state;
4678c2ecf20Sopenharmony_ci		break;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	case WAIT_ENABLED:
4708c2ecf20Sopenharmony_ci		switch (new_state) {
4718c2ecf20Sopenharmony_ci		case UNCONFIGURING:
4728c2ecf20Sopenharmony_ci			vscsi->state = new_state;
4738c2ecf20Sopenharmony_ci			vscsi->flags |= RESPONSE_Q_DOWN;
4748c2ecf20Sopenharmony_ci			vscsi->flags &= ~(SCHEDULE_DISCONNECT |
4758c2ecf20Sopenharmony_ci					  DISCONNECT_SCHEDULED);
4768c2ecf20Sopenharmony_ci			dma_rmb();
4778c2ecf20Sopenharmony_ci			if (vscsi->flags & CFG_SLEEPING) {
4788c2ecf20Sopenharmony_ci				vscsi->flags &= ~CFG_SLEEPING;
4798c2ecf20Sopenharmony_ci				complete(&vscsi->unconfig);
4808c2ecf20Sopenharmony_ci			}
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		/* should never happen */
4848c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
4858c2ecf20Sopenharmony_ci		case ERR_DISCONNECT_RECONNECT:
4868c2ecf20Sopenharmony_ci		case WAIT_IDLE:
4878c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "disconnect: invalid state %d for WAIT_IDLE\n",
4888c2ecf20Sopenharmony_ci				vscsi->state);
4898c2ecf20Sopenharmony_ci			break;
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci		break;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	case WAIT_IDLE:
4948c2ecf20Sopenharmony_ci		switch (new_state) {
4958c2ecf20Sopenharmony_ci		case UNCONFIGURING:
4968c2ecf20Sopenharmony_ci			vscsi->flags |= RESPONSE_Q_DOWN;
4978c2ecf20Sopenharmony_ci			vscsi->state = new_state;
4988c2ecf20Sopenharmony_ci			vscsi->flags &= ~(SCHEDULE_DISCONNECT |
4998c2ecf20Sopenharmony_ci					  DISCONNECT_SCHEDULED);
5008c2ecf20Sopenharmony_ci			ibmvscsis_free_command_q(vscsi);
5018c2ecf20Sopenharmony_ci			break;
5028c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
5038c2ecf20Sopenharmony_ci		case ERR_DISCONNECT_RECONNECT:
5048c2ecf20Sopenharmony_ci			vscsi->state = new_state;
5058c2ecf20Sopenharmony_ci			break;
5068c2ecf20Sopenharmony_ci		}
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/*
5108c2ecf20Sopenharmony_ci	 * Initiator has not done a successful srp login
5118c2ecf20Sopenharmony_ci	 * or has done a successful srp logout ( adapter was not
5128c2ecf20Sopenharmony_ci	 * busy). In the first case there can be responses queued
5138c2ecf20Sopenharmony_ci	 * waiting for space on the initiators response queue (MAD)
5148c2ecf20Sopenharmony_ci	 * The second case the adapter is idle. Assume the worse case,
5158c2ecf20Sopenharmony_ci	 * i.e. the second case.
5168c2ecf20Sopenharmony_ci	 */
5178c2ecf20Sopenharmony_ci	case WAIT_CONNECTION:
5188c2ecf20Sopenharmony_ci	case CONNECTED:
5198c2ecf20Sopenharmony_ci	case SRP_PROCESSING:
5208c2ecf20Sopenharmony_ci		wait_idle = true;
5218c2ecf20Sopenharmony_ci		vscsi->state = new_state;
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* can transition from this state to UNCONFIGURING */
5258c2ecf20Sopenharmony_ci	case UNDEFINED:
5268c2ecf20Sopenharmony_ci		if (new_state == UNCONFIGURING)
5278c2ecf20Sopenharmony_ci			vscsi->state = new_state;
5288c2ecf20Sopenharmony_ci		break;
5298c2ecf20Sopenharmony_ci	default:
5308c2ecf20Sopenharmony_ci		break;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (wait_idle) {
5348c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "disconnect start wait, active %d, sched %d\n",
5358c2ecf20Sopenharmony_ci			(int)list_empty(&vscsi->active_q),
5368c2ecf20Sopenharmony_ci			(int)list_empty(&vscsi->schedule_q));
5378c2ecf20Sopenharmony_ci		if (!list_empty(&vscsi->active_q) ||
5388c2ecf20Sopenharmony_ci		    !list_empty(&vscsi->schedule_q)) {
5398c2ecf20Sopenharmony_ci			vscsi->flags |= WAIT_FOR_IDLE;
5408c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "disconnect flags 0x%x\n",
5418c2ecf20Sopenharmony_ci				vscsi->flags);
5428c2ecf20Sopenharmony_ci			/*
5438c2ecf20Sopenharmony_ci			 * This routine is can not be called with the interrupt
5448c2ecf20Sopenharmony_ci			 * lock held.
5458c2ecf20Sopenharmony_ci			 */
5468c2ecf20Sopenharmony_ci			spin_unlock_bh(&vscsi->intr_lock);
5478c2ecf20Sopenharmony_ci			wait_for_completion(&vscsi->wait_idle);
5488c2ecf20Sopenharmony_ci			spin_lock_bh(&vscsi->intr_lock);
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "disconnect stop wait\n");
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		ibmvscsis_adapter_idle(vscsi);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci/**
5598c2ecf20Sopenharmony_ci * ibmvscsis_post_disconnect() - Schedule the disconnect
5608c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
5618c2ecf20Sopenharmony_ci * @new_state:	State to move to after disconnecting
5628c2ecf20Sopenharmony_ci * @flag_bits:	Flags to turn on in adapter structure
5638c2ecf20Sopenharmony_ci *
5648c2ecf20Sopenharmony_ci * If it's already been scheduled, then see if we need to "upgrade"
5658c2ecf20Sopenharmony_ci * the new state (if the one passed in is more "severe" than the
5668c2ecf20Sopenharmony_ci * previous one).
5678c2ecf20Sopenharmony_ci *
5688c2ecf20Sopenharmony_ci * PRECONDITION:
5698c2ecf20Sopenharmony_ci *	interrupt lock is held
5708c2ecf20Sopenharmony_ci */
5718c2ecf20Sopenharmony_cistatic void ibmvscsis_post_disconnect(struct scsi_info *vscsi, uint new_state,
5728c2ecf20Sopenharmony_ci				      uint flag_bits)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	uint state;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* check the validity of the new state */
5778c2ecf20Sopenharmony_ci	switch (new_state) {
5788c2ecf20Sopenharmony_ci	case UNCONFIGURING:
5798c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
5808c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
5818c2ecf20Sopenharmony_ci	case WAIT_IDLE:
5828c2ecf20Sopenharmony_ci		break;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	default:
5858c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "post_disconnect: Invalid new state %d\n",
5868c2ecf20Sopenharmony_ci			new_state);
5878c2ecf20Sopenharmony_ci		return;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	vscsi->flags |= flag_bits;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "post_disconnect: new_state 0x%x, flag_bits 0x%x, vscsi->flags 0x%x, state %hx\n",
5938c2ecf20Sopenharmony_ci		new_state, flag_bits, vscsi->flags, vscsi->state);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (!(vscsi->flags & (DISCONNECT_SCHEDULED | SCHEDULE_DISCONNECT))) {
5968c2ecf20Sopenharmony_ci		vscsi->flags |= SCHEDULE_DISCONNECT;
5978c2ecf20Sopenharmony_ci		vscsi->new_state = new_state;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		INIT_WORK(&vscsi->proc_work, ibmvscsis_disconnect);
6008c2ecf20Sopenharmony_ci		(void)queue_work(vscsi->work_q, &vscsi->proc_work);
6018c2ecf20Sopenharmony_ci	} else {
6028c2ecf20Sopenharmony_ci		if (vscsi->new_state)
6038c2ecf20Sopenharmony_ci			state = vscsi->new_state;
6048c2ecf20Sopenharmony_ci		else
6058c2ecf20Sopenharmony_ci			state = vscsi->state;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		switch (state) {
6088c2ecf20Sopenharmony_ci		case NO_QUEUE:
6098c2ecf20Sopenharmony_ci		case UNCONFIGURING:
6108c2ecf20Sopenharmony_ci			break;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		case ERR_DISCONNECTED:
6138c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
6148c2ecf20Sopenharmony_ci		case UNDEFINED:
6158c2ecf20Sopenharmony_ci			if (new_state == UNCONFIGURING)
6168c2ecf20Sopenharmony_ci				vscsi->new_state = new_state;
6178c2ecf20Sopenharmony_ci			break;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		case ERR_DISCONNECT_RECONNECT:
6208c2ecf20Sopenharmony_ci			switch (new_state) {
6218c2ecf20Sopenharmony_ci			case UNCONFIGURING:
6228c2ecf20Sopenharmony_ci			case ERR_DISCONNECT:
6238c2ecf20Sopenharmony_ci				vscsi->new_state = new_state;
6248c2ecf20Sopenharmony_ci				break;
6258c2ecf20Sopenharmony_ci			default:
6268c2ecf20Sopenharmony_ci				break;
6278c2ecf20Sopenharmony_ci			}
6288c2ecf20Sopenharmony_ci			break;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		case WAIT_ENABLED:
6318c2ecf20Sopenharmony_ci		case WAIT_IDLE:
6328c2ecf20Sopenharmony_ci		case WAIT_CONNECTION:
6338c2ecf20Sopenharmony_ci		case CONNECTED:
6348c2ecf20Sopenharmony_ci		case SRP_PROCESSING:
6358c2ecf20Sopenharmony_ci			vscsi->new_state = new_state;
6368c2ecf20Sopenharmony_ci			break;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		default:
6398c2ecf20Sopenharmony_ci			break;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving post_disconnect: flags 0x%x, new_state 0x%x\n",
6448c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->new_state);
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci/**
6488c2ecf20Sopenharmony_ci * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message
6498c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
6508c2ecf20Sopenharmony_ci *
6518c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
6528c2ecf20Sopenharmony_ci */
6538c2ecf20Sopenharmony_cistatic long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	switch (vscsi->state) {
6588c2ecf20Sopenharmony_ci	case NO_QUEUE:
6598c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
6608c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
6618c2ecf20Sopenharmony_ci	case ERR_DISCONNECTED:
6628c2ecf20Sopenharmony_ci	case UNCONFIGURING:
6638c2ecf20Sopenharmony_ci	case UNDEFINED:
6648c2ecf20Sopenharmony_ci		rc = ERROR;
6658c2ecf20Sopenharmony_ci		break;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	case WAIT_CONNECTION:
6688c2ecf20Sopenharmony_ci		vscsi->state = CONNECTED;
6698c2ecf20Sopenharmony_ci		break;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	case WAIT_IDLE:
6728c2ecf20Sopenharmony_ci	case SRP_PROCESSING:
6738c2ecf20Sopenharmony_ci	case CONNECTED:
6748c2ecf20Sopenharmony_ci	case WAIT_ENABLED:
6758c2ecf20Sopenharmony_ci	default:
6768c2ecf20Sopenharmony_ci		rc = ERROR;
6778c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
6788c2ecf20Sopenharmony_ci			vscsi->state);
6798c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
6808c2ecf20Sopenharmony_ci		break;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	return rc;
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci/**
6878c2ecf20Sopenharmony_ci * ibmvscsis_handle_init_msg() - Respond to an Init Message
6888c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
6898c2ecf20Sopenharmony_ci *
6908c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
6918c2ecf20Sopenharmony_ci */
6928c2ecf20Sopenharmony_cistatic long ibmvscsis_handle_init_msg(struct scsi_info *vscsi)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	switch (vscsi->state) {
6978c2ecf20Sopenharmony_ci	case WAIT_CONNECTION:
6988c2ecf20Sopenharmony_ci		rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
6998c2ecf20Sopenharmony_ci		switch (rc) {
7008c2ecf20Sopenharmony_ci		case H_SUCCESS:
7018c2ecf20Sopenharmony_ci			vscsi->state = CONNECTED;
7028c2ecf20Sopenharmony_ci			break;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		case H_PARAMETER:
7058c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
7068c2ecf20Sopenharmony_ci				rc);
7078c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
7088c2ecf20Sopenharmony_ci			break;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		case H_DROPPED:
7118c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
7128c2ecf20Sopenharmony_ci				rc);
7138c2ecf20Sopenharmony_ci			rc = ERROR;
7148c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
7158c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
7168c2ecf20Sopenharmony_ci			break;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		case H_CLOSED:
7198c2ecf20Sopenharmony_ci			dev_warn(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
7208c2ecf20Sopenharmony_ci				 rc);
7218c2ecf20Sopenharmony_ci			rc = 0;
7228c2ecf20Sopenharmony_ci			break;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci		break;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	case UNDEFINED:
7278c2ecf20Sopenharmony_ci		rc = ERROR;
7288c2ecf20Sopenharmony_ci		break;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	case UNCONFIGURING:
7318c2ecf20Sopenharmony_ci		break;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	case WAIT_ENABLED:
7348c2ecf20Sopenharmony_ci	case CONNECTED:
7358c2ecf20Sopenharmony_ci	case SRP_PROCESSING:
7368c2ecf20Sopenharmony_ci	case WAIT_IDLE:
7378c2ecf20Sopenharmony_ci	case NO_QUEUE:
7388c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
7398c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
7408c2ecf20Sopenharmony_ci	case ERR_DISCONNECTED:
7418c2ecf20Sopenharmony_ci	default:
7428c2ecf20Sopenharmony_ci		rc = ERROR;
7438c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n",
7448c2ecf20Sopenharmony_ci			vscsi->state);
7458c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
7468c2ecf20Sopenharmony_ci		break;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return rc;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci/**
7538c2ecf20Sopenharmony_ci * ibmvscsis_init_msg() - Respond to an init message
7548c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
7558c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ element containing the Init Message
7568c2ecf20Sopenharmony_ci *
7578c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
7588c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
7598c2ecf20Sopenharmony_ci */
7608c2ecf20Sopenharmony_cistatic long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "init_msg: state 0x%hx\n", vscsi->state);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
7678c2ecf20Sopenharmony_ci		      (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
7688c2ecf20Sopenharmony_ci		      0);
7698c2ecf20Sopenharmony_ci	if (rc == H_SUCCESS) {
7708c2ecf20Sopenharmony_ci		vscsi->client_data.partition_number =
7718c2ecf20Sopenharmony_ci			be64_to_cpu(*(u64 *)vscsi->map_buf);
7728c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "init_msg, part num %d\n",
7738c2ecf20Sopenharmony_ci			vscsi->client_data.partition_number);
7748c2ecf20Sopenharmony_ci	} else {
7758c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "init_msg h_vioctl rc %ld\n", rc);
7768c2ecf20Sopenharmony_ci		rc = ADAPT_SUCCESS;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (crq->format == INIT_MSG) {
7808c2ecf20Sopenharmony_ci		rc = ibmvscsis_handle_init_msg(vscsi);
7818c2ecf20Sopenharmony_ci	} else if (crq->format == INIT_COMPLETE_MSG) {
7828c2ecf20Sopenharmony_ci		rc = ibmvscsis_handle_init_compl_msg(vscsi);
7838c2ecf20Sopenharmony_ci	} else {
7848c2ecf20Sopenharmony_ci		rc = ERROR;
7858c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "init_msg: invalid format %d\n",
7868c2ecf20Sopenharmony_ci			(uint)crq->format);
7878c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return rc;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/**
7948c2ecf20Sopenharmony_ci * ibmvscsis_establish_new_q() - Establish new CRQ queue
7958c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
7968c2ecf20Sopenharmony_ci *
7978c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
7988c2ecf20Sopenharmony_ci */
7998c2ecf20Sopenharmony_cistatic long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
8028c2ecf20Sopenharmony_ci	uint format;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	rc = h_vioctl(vscsi->dds.unit_id, H_ENABLE_PREPARE_FOR_SUSPEND, 30000,
8058c2ecf20Sopenharmony_ci		      0, 0, 0, 0);
8068c2ecf20Sopenharmony_ci	if (rc == H_SUCCESS)
8078c2ecf20Sopenharmony_ci		vscsi->flags |= PREP_FOR_SUSPEND_ENABLED;
8088c2ecf20Sopenharmony_ci	else if (rc != H_NOT_FOUND)
8098c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Error from Enable Prepare for Suspend: %ld\n",
8108c2ecf20Sopenharmony_ci			rc);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	vscsi->flags &= PRESERVE_FLAG_FIELDS;
8138c2ecf20Sopenharmony_ci	vscsi->rsp_q_timer.timer_pops = 0;
8148c2ecf20Sopenharmony_ci	vscsi->debit = 0;
8158c2ecf20Sopenharmony_ci	vscsi->credit = 0;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	rc = vio_enable_interrupts(vscsi->dma_dev);
8188c2ecf20Sopenharmony_ci	if (rc) {
8198c2ecf20Sopenharmony_ci		dev_warn(&vscsi->dev, "establish_new_q: failed to enable interrupts, rc %ld\n",
8208c2ecf20Sopenharmony_ci			 rc);
8218c2ecf20Sopenharmony_ci		return rc;
8228c2ecf20Sopenharmony_ci	}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	rc = ibmvscsis_check_init_msg(vscsi, &format);
8258c2ecf20Sopenharmony_ci	if (rc) {
8268c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "establish_new_q: check_init_msg failed, rc %ld\n",
8278c2ecf20Sopenharmony_ci			rc);
8288c2ecf20Sopenharmony_ci		return rc;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (format == UNUSED_FORMAT) {
8328c2ecf20Sopenharmony_ci		rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
8338c2ecf20Sopenharmony_ci		switch (rc) {
8348c2ecf20Sopenharmony_ci		case H_SUCCESS:
8358c2ecf20Sopenharmony_ci		case H_DROPPED:
8368c2ecf20Sopenharmony_ci		case H_CLOSED:
8378c2ecf20Sopenharmony_ci			rc = ADAPT_SUCCESS;
8388c2ecf20Sopenharmony_ci			break;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		case H_PARAMETER:
8418c2ecf20Sopenharmony_ci		case H_HARDWARE:
8428c2ecf20Sopenharmony_ci			break;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci		default:
8458c2ecf20Sopenharmony_ci			vscsi->state = UNDEFINED;
8468c2ecf20Sopenharmony_ci			rc = H_HARDWARE;
8478c2ecf20Sopenharmony_ci			break;
8488c2ecf20Sopenharmony_ci		}
8498c2ecf20Sopenharmony_ci	} else if (format == INIT_MSG) {
8508c2ecf20Sopenharmony_ci		rc = ibmvscsis_handle_init_msg(vscsi);
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	return rc;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci/**
8578c2ecf20Sopenharmony_ci * ibmvscsis_reset_queue() - Reset CRQ Queue
8588c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
8598c2ecf20Sopenharmony_ci *
8608c2ecf20Sopenharmony_ci * This function calls h_free_q and then calls h_reg_q and does all
8618c2ecf20Sopenharmony_ci * of the bookkeeping to get us back to where we can communicate.
8628c2ecf20Sopenharmony_ci *
8638c2ecf20Sopenharmony_ci * Actually, we don't always call h_free_crq.  A problem was discovered
8648c2ecf20Sopenharmony_ci * where one partition would close and reopen his queue, which would
8658c2ecf20Sopenharmony_ci * cause his partner to get a transport event, which would cause him to
8668c2ecf20Sopenharmony_ci * close and reopen his queue, which would cause the original partition
8678c2ecf20Sopenharmony_ci * to get a transport event, etc., etc.  To prevent this, we don't
8688c2ecf20Sopenharmony_ci * actually close our queue if the client initiated the reset, (i.e.
8698c2ecf20Sopenharmony_ci * either we got a transport event or we have detected that the client's
8708c2ecf20Sopenharmony_ci * queue is gone)
8718c2ecf20Sopenharmony_ci *
8728c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
8738c2ecf20Sopenharmony_ci *	Process environment, called with interrupt lock held
8748c2ecf20Sopenharmony_ci */
8758c2ecf20Sopenharmony_cistatic void ibmvscsis_reset_queue(struct scsi_info *vscsi)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	int bytes;
8788c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "reset_queue: flags 0x%x\n", vscsi->flags);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* don't reset, the client did it for us */
8838c2ecf20Sopenharmony_ci	if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) {
8848c2ecf20Sopenharmony_ci		vscsi->flags &= PRESERVE_FLAG_FIELDS;
8858c2ecf20Sopenharmony_ci		vscsi->rsp_q_timer.timer_pops = 0;
8868c2ecf20Sopenharmony_ci		vscsi->debit = 0;
8878c2ecf20Sopenharmony_ci		vscsi->credit = 0;
8888c2ecf20Sopenharmony_ci		vscsi->state = WAIT_CONNECTION;
8898c2ecf20Sopenharmony_ci		vio_enable_interrupts(vscsi->dma_dev);
8908c2ecf20Sopenharmony_ci	} else {
8918c2ecf20Sopenharmony_ci		rc = ibmvscsis_free_command_q(vscsi);
8928c2ecf20Sopenharmony_ci		if (rc == ADAPT_SUCCESS) {
8938c2ecf20Sopenharmony_ci			vscsi->state = WAIT_CONNECTION;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci			bytes = vscsi->cmd_q.size * PAGE_SIZE;
8968c2ecf20Sopenharmony_ci			rc = h_reg_crq(vscsi->dds.unit_id,
8978c2ecf20Sopenharmony_ci				       vscsi->cmd_q.crq_token, bytes);
8988c2ecf20Sopenharmony_ci			if (rc == H_CLOSED || rc == H_SUCCESS) {
8998c2ecf20Sopenharmony_ci				rc = ibmvscsis_establish_new_q(vscsi);
9008c2ecf20Sopenharmony_ci			}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci			if (rc != ADAPT_SUCCESS) {
9038c2ecf20Sopenharmony_ci				dev_dbg(&vscsi->dev, "reset_queue: reg_crq rc %ld\n",
9048c2ecf20Sopenharmony_ci					rc);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci				vscsi->state = ERR_DISCONNECTED;
9078c2ecf20Sopenharmony_ci				vscsi->flags |= RESPONSE_Q_DOWN;
9088c2ecf20Sopenharmony_ci				ibmvscsis_free_command_q(vscsi);
9098c2ecf20Sopenharmony_ci			}
9108c2ecf20Sopenharmony_ci		} else {
9118c2ecf20Sopenharmony_ci			vscsi->state = ERR_DISCONNECTED;
9128c2ecf20Sopenharmony_ci			vscsi->flags |= RESPONSE_Q_DOWN;
9138c2ecf20Sopenharmony_ci		}
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/**
9188c2ecf20Sopenharmony_ci * ibmvscsis_free_cmd_resources() - Free command resources
9198c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
9208c2ecf20Sopenharmony_ci * @cmd:	Command which is not longer in use
9218c2ecf20Sopenharmony_ci *
9228c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
9238c2ecf20Sopenharmony_ci */
9248c2ecf20Sopenharmony_cistatic void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
9258c2ecf20Sopenharmony_ci					 struct ibmvscsis_cmd *cmd)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	switch (cmd->type) {
9308c2ecf20Sopenharmony_ci	case TASK_MANAGEMENT:
9318c2ecf20Sopenharmony_ci	case SCSI_CDB:
9328c2ecf20Sopenharmony_ci		/*
9338c2ecf20Sopenharmony_ci		 * When the queue goes down this value is cleared, so it
9348c2ecf20Sopenharmony_ci		 * cannot be cleared in this general purpose function.
9358c2ecf20Sopenharmony_ci		 */
9368c2ecf20Sopenharmony_ci		if (vscsi->debit)
9378c2ecf20Sopenharmony_ci			vscsi->debit -= 1;
9388c2ecf20Sopenharmony_ci		break;
9398c2ecf20Sopenharmony_ci	case ADAPTER_MAD:
9408c2ecf20Sopenharmony_ci		vscsi->flags &= ~PROCESSING_MAD;
9418c2ecf20Sopenharmony_ci		break;
9428c2ecf20Sopenharmony_ci	case UNSET_TYPE:
9438c2ecf20Sopenharmony_ci		break;
9448c2ecf20Sopenharmony_ci	default:
9458c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n",
9468c2ecf20Sopenharmony_ci			cmd->type);
9478c2ecf20Sopenharmony_ci		break;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	cmd->iue = NULL;
9518c2ecf20Sopenharmony_ci	list_add_tail(&cmd->list, &vscsi->free_cmd);
9528c2ecf20Sopenharmony_ci	srp_iu_put(iue);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) &&
9558c2ecf20Sopenharmony_ci	    list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) {
9568c2ecf20Sopenharmony_ci		vscsi->flags &= ~WAIT_FOR_IDLE;
9578c2ecf20Sopenharmony_ci		complete(&vscsi->wait_idle);
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci/**
9628c2ecf20Sopenharmony_ci * ibmvscsis_ready_for_suspend() - Helper function to call VIOCTL
9638c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
9648c2ecf20Sopenharmony_ci * @idle:	Indicates whether we were called from adapter_idle.  This
9658c2ecf20Sopenharmony_ci *		is important to know if we need to do a disconnect, since if
9668c2ecf20Sopenharmony_ci *		we're called from adapter_idle, we're still processing the
9678c2ecf20Sopenharmony_ci *		current disconnect, so we can't just call post_disconnect.
9688c2ecf20Sopenharmony_ci *
9698c2ecf20Sopenharmony_ci * This function is called when the adapter is idle when phyp has sent
9708c2ecf20Sopenharmony_ci * us a Prepare for Suspend Transport Event.
9718c2ecf20Sopenharmony_ci *
9728c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
9738c2ecf20Sopenharmony_ci *	Process or interrupt environment called with interrupt lock held
9748c2ecf20Sopenharmony_ci */
9758c2ecf20Sopenharmony_cistatic long ibmvscsis_ready_for_suspend(struct scsi_info *vscsi, bool idle)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	long rc = 0;
9788c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	/* See if there is a Resume event in the queue */
9818c2ecf20Sopenharmony_ci	crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "ready_suspend: flags 0x%x, state 0x%hx crq_valid:%x\n",
9848c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state, (int)crq->valid);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (!(vscsi->flags & PREP_FOR_SUSPEND_ABORTED) && !(crq->valid)) {
9878c2ecf20Sopenharmony_ci		rc = h_vioctl(vscsi->dds.unit_id, H_READY_FOR_SUSPEND, 0, 0, 0,
9888c2ecf20Sopenharmony_ci			      0, 0);
9898c2ecf20Sopenharmony_ci		if (rc) {
9908c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "Ready for Suspend Vioctl failed: %ld\n",
9918c2ecf20Sopenharmony_ci				rc);
9928c2ecf20Sopenharmony_ci			rc = 0;
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci	} else if (((vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE) &&
9958c2ecf20Sopenharmony_ci		    (vscsi->flags & PREP_FOR_SUSPEND_ABORTED)) ||
9968c2ecf20Sopenharmony_ci		   ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
9978c2ecf20Sopenharmony_ci				     (crq->format != RESUME_FROM_SUSP)))) {
9988c2ecf20Sopenharmony_ci		if (idle) {
9998c2ecf20Sopenharmony_ci			vscsi->state = ERR_DISCONNECT_RECONNECT;
10008c2ecf20Sopenharmony_ci			ibmvscsis_reset_queue(vscsi);
10018c2ecf20Sopenharmony_ci			rc = -1;
10028c2ecf20Sopenharmony_ci		} else if (vscsi->state == CONNECTED) {
10038c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
10048c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
10058c2ecf20Sopenharmony_ci		}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci		vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		if ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
10108c2ecf20Sopenharmony_ci				     (crq->format != RESUME_FROM_SUSP)))
10118c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "Invalid element in CRQ after Prepare for Suspend");
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	vscsi->flags &= ~(PREP_FOR_SUSPEND_PENDING | PREP_FOR_SUSPEND_ABORTED);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	return rc;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci/**
10208c2ecf20Sopenharmony_ci * ibmvscsis_trans_event() - Handle a Transport Event
10218c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
10228c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ entry containing the Transport Event
10238c2ecf20Sopenharmony_ci *
10248c2ecf20Sopenharmony_ci * Do the logic to close the I_T nexus.  This function may not
10258c2ecf20Sopenharmony_ci * behave to specification.
10268c2ecf20Sopenharmony_ci *
10278c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
10288c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
10298c2ecf20Sopenharmony_ci */
10308c2ecf20Sopenharmony_cistatic long ibmvscsis_trans_event(struct scsi_info *vscsi,
10318c2ecf20Sopenharmony_ci				  struct viosrp_crq *crq)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "trans_event: format %d, flags 0x%x, state 0x%hx\n",
10368c2ecf20Sopenharmony_ci		(int)crq->format, vscsi->flags, vscsi->state);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	switch (crq->format) {
10398c2ecf20Sopenharmony_ci	case MIGRATED:
10408c2ecf20Sopenharmony_ci	case PARTNER_FAILED:
10418c2ecf20Sopenharmony_ci	case PARTNER_DEREGISTER:
10428c2ecf20Sopenharmony_ci		ibmvscsis_delete_client_info(vscsi, true);
10438c2ecf20Sopenharmony_ci		if (crq->format == MIGRATED)
10448c2ecf20Sopenharmony_ci			vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
10458c2ecf20Sopenharmony_ci		switch (vscsi->state) {
10468c2ecf20Sopenharmony_ci		case NO_QUEUE:
10478c2ecf20Sopenharmony_ci		case ERR_DISCONNECTED:
10488c2ecf20Sopenharmony_ci		case UNDEFINED:
10498c2ecf20Sopenharmony_ci			break;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		case UNCONFIGURING:
10528c2ecf20Sopenharmony_ci			vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
10538c2ecf20Sopenharmony_ci			break;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci		case WAIT_ENABLED:
10568c2ecf20Sopenharmony_ci			break;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		case WAIT_CONNECTION:
10598c2ecf20Sopenharmony_ci			break;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		case CONNECTED:
10628c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
10638c2ecf20Sopenharmony_ci						  (RESPONSE_Q_DOWN |
10648c2ecf20Sopenharmony_ci						   TRANS_EVENT));
10658c2ecf20Sopenharmony_ci			break;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		case SRP_PROCESSING:
10688c2ecf20Sopenharmony_ci			if ((vscsi->debit > 0) ||
10698c2ecf20Sopenharmony_ci			    !list_empty(&vscsi->schedule_q) ||
10708c2ecf20Sopenharmony_ci			    !list_empty(&vscsi->waiting_rsp) ||
10718c2ecf20Sopenharmony_ci			    !list_empty(&vscsi->active_q)) {
10728c2ecf20Sopenharmony_ci				dev_dbg(&vscsi->dev, "debit %d, sched %d, wait %d, active %d\n",
10738c2ecf20Sopenharmony_ci					vscsi->debit,
10748c2ecf20Sopenharmony_ci					(int)list_empty(&vscsi->schedule_q),
10758c2ecf20Sopenharmony_ci					(int)list_empty(&vscsi->waiting_rsp),
10768c2ecf20Sopenharmony_ci					(int)list_empty(&vscsi->active_q));
10778c2ecf20Sopenharmony_ci				dev_warn(&vscsi->dev, "connection lost with outstanding work\n");
10788c2ecf20Sopenharmony_ci			} else {
10798c2ecf20Sopenharmony_ci				dev_dbg(&vscsi->dev, "trans_event: SRP Processing, but no outstanding work\n");
10808c2ecf20Sopenharmony_ci			}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
10838c2ecf20Sopenharmony_ci						  (RESPONSE_Q_DOWN |
10848c2ecf20Sopenharmony_ci						   TRANS_EVENT));
10858c2ecf20Sopenharmony_ci			break;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
10888c2ecf20Sopenharmony_ci		case ERR_DISCONNECT_RECONNECT:
10898c2ecf20Sopenharmony_ci		case WAIT_IDLE:
10908c2ecf20Sopenharmony_ci			vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
10918c2ecf20Sopenharmony_ci			break;
10928c2ecf20Sopenharmony_ci		}
10938c2ecf20Sopenharmony_ci		break;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	case PREPARE_FOR_SUSPEND:
10968c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "Prep for Suspend, crq status = 0x%x\n",
10978c2ecf20Sopenharmony_ci			(int)crq->status);
10988c2ecf20Sopenharmony_ci		switch (vscsi->state) {
10998c2ecf20Sopenharmony_ci		case ERR_DISCONNECTED:
11008c2ecf20Sopenharmony_ci		case WAIT_CONNECTION:
11018c2ecf20Sopenharmony_ci		case CONNECTED:
11028c2ecf20Sopenharmony_ci			ibmvscsis_ready_for_suspend(vscsi, false);
11038c2ecf20Sopenharmony_ci			break;
11048c2ecf20Sopenharmony_ci		case SRP_PROCESSING:
11058c2ecf20Sopenharmony_ci			vscsi->resume_state = vscsi->state;
11068c2ecf20Sopenharmony_ci			vscsi->flags |= PREP_FOR_SUSPEND_PENDING;
11078c2ecf20Sopenharmony_ci			if (crq->status == CRQ_ENTRY_OVERWRITTEN)
11088c2ecf20Sopenharmony_ci				vscsi->flags |= PREP_FOR_SUSPEND_OVERWRITE;
11098c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
11108c2ecf20Sopenharmony_ci			break;
11118c2ecf20Sopenharmony_ci		case NO_QUEUE:
11128c2ecf20Sopenharmony_ci		case UNDEFINED:
11138c2ecf20Sopenharmony_ci		case UNCONFIGURING:
11148c2ecf20Sopenharmony_ci		case WAIT_ENABLED:
11158c2ecf20Sopenharmony_ci		case ERR_DISCONNECT:
11168c2ecf20Sopenharmony_ci		case ERR_DISCONNECT_RECONNECT:
11178c2ecf20Sopenharmony_ci		case WAIT_IDLE:
11188c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "Invalid state for Prepare for Suspend Trans Event: 0x%x\n",
11198c2ecf20Sopenharmony_ci				vscsi->state);
11208c2ecf20Sopenharmony_ci			break;
11218c2ecf20Sopenharmony_ci		}
11228c2ecf20Sopenharmony_ci		break;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	case RESUME_FROM_SUSP:
11258c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "Resume from Suspend, crq status = 0x%x\n",
11268c2ecf20Sopenharmony_ci			(int)crq->status);
11278c2ecf20Sopenharmony_ci		if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
11288c2ecf20Sopenharmony_ci			vscsi->flags |= PREP_FOR_SUSPEND_ABORTED;
11298c2ecf20Sopenharmony_ci		} else {
11308c2ecf20Sopenharmony_ci			if ((crq->status == CRQ_ENTRY_OVERWRITTEN) ||
11318c2ecf20Sopenharmony_ci			    (vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE)) {
11328c2ecf20Sopenharmony_ci				ibmvscsis_post_disconnect(vscsi,
11338c2ecf20Sopenharmony_ci							  ERR_DISCONNECT_RECONNECT,
11348c2ecf20Sopenharmony_ci							  0);
11358c2ecf20Sopenharmony_ci				vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
11368c2ecf20Sopenharmony_ci			}
11378c2ecf20Sopenharmony_ci		}
11388c2ecf20Sopenharmony_ci		break;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	default:
11418c2ecf20Sopenharmony_ci		rc = ERROR;
11428c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
11438c2ecf20Sopenharmony_ci			(uint)crq->format);
11448c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
11458c2ecf20Sopenharmony_ci					  RESPONSE_Q_DOWN);
11468c2ecf20Sopenharmony_ci		break;
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	rc = vscsi->flags & SCHEDULE_DISCONNECT;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving trans_event: flags 0x%x, state 0x%hx, rc %ld\n",
11528c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state, rc);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	return rc;
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci/**
11588c2ecf20Sopenharmony_ci * ibmvscsis_poll_cmd_q() - Poll Command Queue
11598c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
11608c2ecf20Sopenharmony_ci *
11618c2ecf20Sopenharmony_ci * Called to handle command elements that may have arrived while
11628c2ecf20Sopenharmony_ci * interrupts were disabled.
11638c2ecf20Sopenharmony_ci *
11648c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
11658c2ecf20Sopenharmony_ci *	intr_lock must be held
11668c2ecf20Sopenharmony_ci */
11678c2ecf20Sopenharmony_cistatic void ibmvscsis_poll_cmd_q(struct scsi_info *vscsi)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
11708c2ecf20Sopenharmony_ci	long rc;
11718c2ecf20Sopenharmony_ci	bool ack = true;
11728c2ecf20Sopenharmony_ci	volatile u8 valid;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "poll_cmd_q: flags 0x%x, state 0x%hx, q index %ud\n",
11758c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state, vscsi->cmd_q.index);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	rc = vscsi->flags & SCHEDULE_DISCONNECT;
11788c2ecf20Sopenharmony_ci	crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
11798c2ecf20Sopenharmony_ci	valid = crq->valid;
11808c2ecf20Sopenharmony_ci	dma_rmb();
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	while (valid) {
11838c2ecf20Sopenharmony_cipoll_work:
11848c2ecf20Sopenharmony_ci		vscsi->cmd_q.index =
11858c2ecf20Sopenharmony_ci			(vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci		if (!rc) {
11888c2ecf20Sopenharmony_ci			rc = ibmvscsis_parse_command(vscsi, crq);
11898c2ecf20Sopenharmony_ci		} else {
11908c2ecf20Sopenharmony_ci			if ((uint)crq->valid == VALID_TRANS_EVENT) {
11918c2ecf20Sopenharmony_ci				/*
11928c2ecf20Sopenharmony_ci				 * must service the transport layer events even
11938c2ecf20Sopenharmony_ci				 * in an error state, dont break out until all
11948c2ecf20Sopenharmony_ci				 * the consecutive transport events have been
11958c2ecf20Sopenharmony_ci				 * processed
11968c2ecf20Sopenharmony_ci				 */
11978c2ecf20Sopenharmony_ci				rc = ibmvscsis_trans_event(vscsi, crq);
11988c2ecf20Sopenharmony_ci			} else if (vscsi->flags & TRANS_EVENT) {
11998c2ecf20Sopenharmony_ci				/*
12008c2ecf20Sopenharmony_ci				 * if a tranport event has occurred leave
12018c2ecf20Sopenharmony_ci				 * everything but transport events on the queue
12028c2ecf20Sopenharmony_ci				 */
12038c2ecf20Sopenharmony_ci				dev_dbg(&vscsi->dev, "poll_cmd_q, ignoring\n");
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci				/*
12068c2ecf20Sopenharmony_ci				 * need to decrement the queue index so we can
12078c2ecf20Sopenharmony_ci				 * look at the elment again
12088c2ecf20Sopenharmony_ci				 */
12098c2ecf20Sopenharmony_ci				if (vscsi->cmd_q.index)
12108c2ecf20Sopenharmony_ci					vscsi->cmd_q.index -= 1;
12118c2ecf20Sopenharmony_ci				else
12128c2ecf20Sopenharmony_ci					/*
12138c2ecf20Sopenharmony_ci					 * index is at 0 it just wrapped.
12148c2ecf20Sopenharmony_ci					 * have it index last element in q
12158c2ecf20Sopenharmony_ci					 */
12168c2ecf20Sopenharmony_ci					vscsi->cmd_q.index = vscsi->cmd_q.mask;
12178c2ecf20Sopenharmony_ci				break;
12188c2ecf20Sopenharmony_ci			}
12198c2ecf20Sopenharmony_ci		}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		crq->valid = INVALIDATE_CMD_RESP_EL;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci		crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
12248c2ecf20Sopenharmony_ci		valid = crq->valid;
12258c2ecf20Sopenharmony_ci		dma_rmb();
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if (!rc) {
12298c2ecf20Sopenharmony_ci		if (ack) {
12308c2ecf20Sopenharmony_ci			vio_enable_interrupts(vscsi->dma_dev);
12318c2ecf20Sopenharmony_ci			ack = false;
12328c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "poll_cmd_q, reenabling interrupts\n");
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci		valid = crq->valid;
12358c2ecf20Sopenharmony_ci		dma_rmb();
12368c2ecf20Sopenharmony_ci		if (valid)
12378c2ecf20Sopenharmony_ci			goto poll_work;
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving poll_cmd_q: rc %ld\n", rc);
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci/**
12448c2ecf20Sopenharmony_ci * ibmvscsis_free_cmd_qs() - Free elements in queue
12458c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
12468c2ecf20Sopenharmony_ci *
12478c2ecf20Sopenharmony_ci * Free all of the elements on all queues that are waiting for
12488c2ecf20Sopenharmony_ci * whatever reason.
12498c2ecf20Sopenharmony_ci *
12508c2ecf20Sopenharmony_ci * PRECONDITION:
12518c2ecf20Sopenharmony_ci *	Called with interrupt lock held
12528c2ecf20Sopenharmony_ci */
12538c2ecf20Sopenharmony_cistatic void ibmvscsis_free_cmd_qs(struct scsi_info *vscsi)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd, *nxt;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "free_cmd_qs: waiting_rsp empty %d, timer starter %d\n",
12588c2ecf20Sopenharmony_ci		(int)list_empty(&vscsi->waiting_rsp),
12598c2ecf20Sopenharmony_ci		vscsi->rsp_q_timer.started);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
12628c2ecf20Sopenharmony_ci		list_del(&cmd->list);
12638c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci/**
12688c2ecf20Sopenharmony_ci * ibmvscsis_get_free_cmd() - Get free command from list
12698c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
12708c2ecf20Sopenharmony_ci *
12718c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
12728c2ecf20Sopenharmony_ci */
12738c2ecf20Sopenharmony_cistatic struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = NULL;
12768c2ecf20Sopenharmony_ci	struct iu_entry *iue;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	iue = srp_iu_get(&vscsi->target);
12798c2ecf20Sopenharmony_ci	if (iue) {
12808c2ecf20Sopenharmony_ci		cmd = list_first_entry_or_null(&vscsi->free_cmd,
12818c2ecf20Sopenharmony_ci					       struct ibmvscsis_cmd, list);
12828c2ecf20Sopenharmony_ci		if (cmd) {
12838c2ecf20Sopenharmony_ci			if (cmd->abort_cmd)
12848c2ecf20Sopenharmony_ci				cmd->abort_cmd = NULL;
12858c2ecf20Sopenharmony_ci			cmd->flags &= ~(DELAY_SEND);
12868c2ecf20Sopenharmony_ci			list_del(&cmd->list);
12878c2ecf20Sopenharmony_ci			cmd->iue = iue;
12888c2ecf20Sopenharmony_ci			cmd->type = UNSET_TYPE;
12898c2ecf20Sopenharmony_ci			memset(&cmd->se_cmd, 0, sizeof(cmd->se_cmd));
12908c2ecf20Sopenharmony_ci		} else {
12918c2ecf20Sopenharmony_ci			srp_iu_put(iue);
12928c2ecf20Sopenharmony_ci		}
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	return cmd;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci/**
12998c2ecf20Sopenharmony_ci * ibmvscsis_adapter_idle() - Helper function to handle idle adapter
13008c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
13018c2ecf20Sopenharmony_ci *
13028c2ecf20Sopenharmony_ci * This function is called when the adapter is idle when the driver
13038c2ecf20Sopenharmony_ci * is attempting to clear an error condition.
13048c2ecf20Sopenharmony_ci * The adapter is considered busy if any of its cmd queues
13058c2ecf20Sopenharmony_ci * are non-empty. This function can be invoked
13068c2ecf20Sopenharmony_ci * from the off level disconnect function.
13078c2ecf20Sopenharmony_ci *
13088c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
13098c2ecf20Sopenharmony_ci *	Process environment called with interrupt lock held
13108c2ecf20Sopenharmony_ci */
13118c2ecf20Sopenharmony_cistatic void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
13128c2ecf20Sopenharmony_ci{
13138c2ecf20Sopenharmony_ci	int free_qs = false;
13148c2ecf20Sopenharmony_ci	long rc = 0;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "adapter_idle: flags 0x%x, state 0x%hx\n",
13178c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	/* Only need to free qs if we're disconnecting from client */
13208c2ecf20Sopenharmony_ci	if (vscsi->state != WAIT_CONNECTION || vscsi->flags & TRANS_EVENT)
13218c2ecf20Sopenharmony_ci		free_qs = true;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	switch (vscsi->state) {
13248c2ecf20Sopenharmony_ci	case UNCONFIGURING:
13258c2ecf20Sopenharmony_ci		ibmvscsis_free_command_q(vscsi);
13268c2ecf20Sopenharmony_ci		dma_rmb();
13278c2ecf20Sopenharmony_ci		isync();
13288c2ecf20Sopenharmony_ci		if (vscsi->flags & CFG_SLEEPING) {
13298c2ecf20Sopenharmony_ci			vscsi->flags &= ~CFG_SLEEPING;
13308c2ecf20Sopenharmony_ci			complete(&vscsi->unconfig);
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci		break;
13338c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
13348c2ecf20Sopenharmony_ci		ibmvscsis_reset_queue(vscsi);
13358c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_idle, disc_rec: flags 0x%x\n",
13368c2ecf20Sopenharmony_ci			vscsi->flags);
13378c2ecf20Sopenharmony_ci		break;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
13408c2ecf20Sopenharmony_ci		ibmvscsis_free_command_q(vscsi);
13418c2ecf20Sopenharmony_ci		vscsi->flags &= ~(SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED);
13428c2ecf20Sopenharmony_ci		vscsi->flags |= RESPONSE_Q_DOWN;
13438c2ecf20Sopenharmony_ci		if (vscsi->tport.enabled)
13448c2ecf20Sopenharmony_ci			vscsi->state = ERR_DISCONNECTED;
13458c2ecf20Sopenharmony_ci		else
13468c2ecf20Sopenharmony_ci			vscsi->state = WAIT_ENABLED;
13478c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_idle, disc: flags 0x%x, state 0x%hx\n",
13488c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state);
13498c2ecf20Sopenharmony_ci		break;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	case WAIT_IDLE:
13528c2ecf20Sopenharmony_ci		vscsi->rsp_q_timer.timer_pops = 0;
13538c2ecf20Sopenharmony_ci		vscsi->debit = 0;
13548c2ecf20Sopenharmony_ci		vscsi->credit = 0;
13558c2ecf20Sopenharmony_ci		if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
13568c2ecf20Sopenharmony_ci			vscsi->state = vscsi->resume_state;
13578c2ecf20Sopenharmony_ci			vscsi->resume_state = 0;
13588c2ecf20Sopenharmony_ci			rc = ibmvscsis_ready_for_suspend(vscsi, true);
13598c2ecf20Sopenharmony_ci			vscsi->flags &= ~DISCONNECT_SCHEDULED;
13608c2ecf20Sopenharmony_ci			if (rc)
13618c2ecf20Sopenharmony_ci				break;
13628c2ecf20Sopenharmony_ci		} else if (vscsi->flags & TRANS_EVENT) {
13638c2ecf20Sopenharmony_ci			vscsi->state = WAIT_CONNECTION;
13648c2ecf20Sopenharmony_ci			vscsi->flags &= PRESERVE_FLAG_FIELDS;
13658c2ecf20Sopenharmony_ci		} else {
13668c2ecf20Sopenharmony_ci			vscsi->state = CONNECTED;
13678c2ecf20Sopenharmony_ci			vscsi->flags &= ~DISCONNECT_SCHEDULED;
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_idle, wait: flags 0x%x, state 0x%hx\n",
13718c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state);
13728c2ecf20Sopenharmony_ci		ibmvscsis_poll_cmd_q(vscsi);
13738c2ecf20Sopenharmony_ci		break;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	case ERR_DISCONNECTED:
13768c2ecf20Sopenharmony_ci		vscsi->flags &= ~DISCONNECT_SCHEDULED;
13778c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_idle, disconnected: flags 0x%x, state 0x%hx\n",
13788c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state);
13798c2ecf20Sopenharmony_ci		break;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	default:
13828c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "adapter_idle: in invalid state %d\n",
13838c2ecf20Sopenharmony_ci			vscsi->state);
13848c2ecf20Sopenharmony_ci		break;
13858c2ecf20Sopenharmony_ci	}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	if (free_qs)
13888c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_qs(vscsi);
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	/*
13918c2ecf20Sopenharmony_ci	 * There is a timing window where we could lose a disconnect request.
13928c2ecf20Sopenharmony_ci	 * The known path to this window occurs during the DISCONNECT_RECONNECT
13938c2ecf20Sopenharmony_ci	 * case above: reset_queue calls free_command_q, which will release the
13948c2ecf20Sopenharmony_ci	 * interrupt lock.  During that time, a new post_disconnect call can be
13958c2ecf20Sopenharmony_ci	 * made with a "more severe" state (DISCONNECT or UNCONFIGURING).
13968c2ecf20Sopenharmony_ci	 * Because the DISCONNECT_SCHEDULED flag is already set, post_disconnect
13978c2ecf20Sopenharmony_ci	 * will only set the new_state.  Now free_command_q reacquires the intr
13988c2ecf20Sopenharmony_ci	 * lock and clears the DISCONNECT_SCHEDULED flag (using PRESERVE_FLAG_
13998c2ecf20Sopenharmony_ci	 * FIELDS), and the disconnect is lost.  This is particularly bad when
14008c2ecf20Sopenharmony_ci	 * the new disconnect was for UNCONFIGURING, since the unconfigure hangs
14018c2ecf20Sopenharmony_ci	 * forever.
14028c2ecf20Sopenharmony_ci	 * Fix is that free command queue sets acr state and acr flags if there
14038c2ecf20Sopenharmony_ci	 * is a change under the lock
14048c2ecf20Sopenharmony_ci	 * note free command queue writes to this state it clears it
14058c2ecf20Sopenharmony_ci	 * before releasing the lock, different drivers call the free command
14068c2ecf20Sopenharmony_ci	 * queue different times so dont initialize above
14078c2ecf20Sopenharmony_ci	 */
14088c2ecf20Sopenharmony_ci	if (vscsi->phyp_acr_state != 0)	{
14098c2ecf20Sopenharmony_ci		/*
14108c2ecf20Sopenharmony_ci		 * set any bits in flags that may have been cleared by
14118c2ecf20Sopenharmony_ci		 * a call to free command queue in switch statement
14128c2ecf20Sopenharmony_ci		 * or reset queue
14138c2ecf20Sopenharmony_ci		 */
14148c2ecf20Sopenharmony_ci		vscsi->flags |= vscsi->phyp_acr_flags;
14158c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, vscsi->phyp_acr_state, 0);
14168c2ecf20Sopenharmony_ci		vscsi->phyp_acr_state = 0;
14178c2ecf20Sopenharmony_ci		vscsi->phyp_acr_flags = 0;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_idle: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
14208c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
14218c2ecf20Sopenharmony_ci			vscsi->phyp_acr_state);
14228c2ecf20Sopenharmony_ci	}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving adapter_idle: flags 0x%x, state 0x%hx, new_state 0x%x\n",
14258c2ecf20Sopenharmony_ci		vscsi->flags, vscsi->state, vscsi->new_state);
14268c2ecf20Sopenharmony_ci}
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci/**
14298c2ecf20Sopenharmony_ci * ibmvscsis_copy_crq_packet() - Copy CRQ Packet
14308c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
14318c2ecf20Sopenharmony_ci * @cmd:	Pointer to command element to use to process the request
14328c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ entry containing the request
14338c2ecf20Sopenharmony_ci *
14348c2ecf20Sopenharmony_ci * Copy the srp information unit from the hosted
14358c2ecf20Sopenharmony_ci * partition using remote dma
14368c2ecf20Sopenharmony_ci *
14378c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
14388c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
14398c2ecf20Sopenharmony_ci */
14408c2ecf20Sopenharmony_cistatic long ibmvscsis_copy_crq_packet(struct scsi_info *vscsi,
14418c2ecf20Sopenharmony_ci				      struct ibmvscsis_cmd *cmd,
14428c2ecf20Sopenharmony_ci				      struct viosrp_crq *crq)
14438c2ecf20Sopenharmony_ci{
14448c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
14458c2ecf20Sopenharmony_ci	long rc = 0;
14468c2ecf20Sopenharmony_ci	u16 len;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	len = be16_to_cpu(crq->IU_length);
14498c2ecf20Sopenharmony_ci	if ((len > SRP_MAX_IU_LEN) || (len == 0)) {
14508c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "copy_crq: Invalid len %d passed", len);
14518c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
14528c2ecf20Sopenharmony_ci		return SRP_VIOLATION;
14538c2ecf20Sopenharmony_ci	}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	rc = h_copy_rdma(len, vscsi->dds.window[REMOTE].liobn,
14568c2ecf20Sopenharmony_ci			 be64_to_cpu(crq->IU_data_ptr),
14578c2ecf20Sopenharmony_ci			 vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	switch (rc) {
14608c2ecf20Sopenharmony_ci	case H_SUCCESS:
14618c2ecf20Sopenharmony_ci		cmd->init_time = mftb();
14628c2ecf20Sopenharmony_ci		iue->remote_token = crq->IU_data_ptr;
14638c2ecf20Sopenharmony_ci		iue->iu_len = len;
14648c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "copy_crq: ioba 0x%llx, init_time 0x%llx\n",
14658c2ecf20Sopenharmony_ci			be64_to_cpu(crq->IU_data_ptr), cmd->init_time);
14668c2ecf20Sopenharmony_ci		break;
14678c2ecf20Sopenharmony_ci	case H_PERMISSION:
14688c2ecf20Sopenharmony_ci		if (connection_broken(vscsi))
14698c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
14708c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT,
14718c2ecf20Sopenharmony_ci						  (RESPONSE_Q_DOWN |
14728c2ecf20Sopenharmony_ci						   CLIENT_FAILED));
14738c2ecf20Sopenharmony_ci		else
14748c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
14758c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
14788c2ecf20Sopenharmony_ci			rc);
14798c2ecf20Sopenharmony_ci		break;
14808c2ecf20Sopenharmony_ci	case H_DEST_PARM:
14818c2ecf20Sopenharmony_ci	case H_SOURCE_PARM:
14828c2ecf20Sopenharmony_ci	default:
14838c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
14848c2ecf20Sopenharmony_ci			rc);
14858c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
14868c2ecf20Sopenharmony_ci		break;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	return rc;
14908c2ecf20Sopenharmony_ci}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci/**
14938c2ecf20Sopenharmony_ci * ibmvscsis_adapter_info - Service an Adapter Info MAnagement Data gram
14948c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
14958c2ecf20Sopenharmony_ci * @iue:	Information Unit containing the Adapter Info MAD request
14968c2ecf20Sopenharmony_ci *
14978c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
14988c2ecf20Sopenharmony_ci *	Interrupt adapter lock is held
14998c2ecf20Sopenharmony_ci */
15008c2ecf20Sopenharmony_cistatic long ibmvscsis_adapter_info(struct scsi_info *vscsi,
15018c2ecf20Sopenharmony_ci				   struct iu_entry *iue)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
15048c2ecf20Sopenharmony_ci	struct mad_adapter_info_data *info;
15058c2ecf20Sopenharmony_ci	uint flag_bits = 0;
15068c2ecf20Sopenharmony_ci	dma_addr_t token;
15078c2ecf20Sopenharmony_ci	long rc;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
15128c2ecf20Sopenharmony_ci		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
15138c2ecf20Sopenharmony_ci		return 0;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token,
15178c2ecf20Sopenharmony_ci				  GFP_ATOMIC);
15188c2ecf20Sopenharmony_ci	if (!info) {
15198c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
15208c2ecf20Sopenharmony_ci			iue->target);
15218c2ecf20Sopenharmony_ci		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
15228c2ecf20Sopenharmony_ci		return 0;
15238c2ecf20Sopenharmony_ci	}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	/* Get remote info */
15268c2ecf20Sopenharmony_ci	rc = h_copy_rdma(be16_to_cpu(mad->common.length),
15278c2ecf20Sopenharmony_ci			 vscsi->dds.window[REMOTE].liobn,
15288c2ecf20Sopenharmony_ci			 be64_to_cpu(mad->buffer),
15298c2ecf20Sopenharmony_ci			 vscsi->dds.window[LOCAL].liobn, token);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if (rc != H_SUCCESS) {
15328c2ecf20Sopenharmony_ci		if (rc == H_PERMISSION) {
15338c2ecf20Sopenharmony_ci			if (connection_broken(vscsi))
15348c2ecf20Sopenharmony_ci				flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
15358c2ecf20Sopenharmony_ci		}
15368c2ecf20Sopenharmony_ci		dev_warn(&vscsi->dev, "adapter_info: h_copy_rdma from client failed, rc %ld\n",
15378c2ecf20Sopenharmony_ci			 rc);
15388c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "adapter_info: ioba 0x%llx, flags 0x%x, flag_bits 0x%x\n",
15398c2ecf20Sopenharmony_ci			be64_to_cpu(mad->buffer), vscsi->flags, flag_bits);
15408c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
15418c2ecf20Sopenharmony_ci					  flag_bits);
15428c2ecf20Sopenharmony_ci		goto free_dma;
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	/*
15468c2ecf20Sopenharmony_ci	 * Copy client info, but ignore partition number, which we
15478c2ecf20Sopenharmony_ci	 * already got from phyp - unless we failed to get it from
15488c2ecf20Sopenharmony_ci	 * phyp (e.g. if we're running on a p5 system).
15498c2ecf20Sopenharmony_ci	 */
15508c2ecf20Sopenharmony_ci	if (vscsi->client_data.partition_number == 0)
15518c2ecf20Sopenharmony_ci		vscsi->client_data.partition_number =
15528c2ecf20Sopenharmony_ci			be32_to_cpu(info->partition_number);
15538c2ecf20Sopenharmony_ci	strncpy(vscsi->client_data.srp_version, info->srp_version,
15548c2ecf20Sopenharmony_ci		sizeof(vscsi->client_data.srp_version));
15558c2ecf20Sopenharmony_ci	strncpy(vscsi->client_data.partition_name, info->partition_name,
15568c2ecf20Sopenharmony_ci		sizeof(vscsi->client_data.partition_name));
15578c2ecf20Sopenharmony_ci	vscsi->client_data.mad_version = be32_to_cpu(info->mad_version);
15588c2ecf20Sopenharmony_ci	vscsi->client_data.os_type = be32_to_cpu(info->os_type);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	/* Copy our info */
15618c2ecf20Sopenharmony_ci	strncpy(info->srp_version, SRP_VERSION,
15628c2ecf20Sopenharmony_ci		sizeof(info->srp_version));
15638c2ecf20Sopenharmony_ci	strncpy(info->partition_name, vscsi->dds.partition_name,
15648c2ecf20Sopenharmony_ci		sizeof(info->partition_name));
15658c2ecf20Sopenharmony_ci	info->partition_number = cpu_to_be32(vscsi->dds.partition_num);
15668c2ecf20Sopenharmony_ci	info->mad_version = cpu_to_be32(MAD_VERSION_1);
15678c2ecf20Sopenharmony_ci	info->os_type = cpu_to_be32(LINUX);
15688c2ecf20Sopenharmony_ci	memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
15698c2ecf20Sopenharmony_ci	info->port_max_txu[0] = cpu_to_be32(MAX_TXU);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	dma_wmb();
15728c2ecf20Sopenharmony_ci	rc = h_copy_rdma(sizeof(*info), vscsi->dds.window[LOCAL].liobn,
15738c2ecf20Sopenharmony_ci			 token, vscsi->dds.window[REMOTE].liobn,
15748c2ecf20Sopenharmony_ci			 be64_to_cpu(mad->buffer));
15758c2ecf20Sopenharmony_ci	switch (rc) {
15768c2ecf20Sopenharmony_ci	case H_SUCCESS:
15778c2ecf20Sopenharmony_ci		break;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	case H_SOURCE_PARM:
15808c2ecf20Sopenharmony_ci	case H_DEST_PARM:
15818c2ecf20Sopenharmony_ci	case H_PERMISSION:
15828c2ecf20Sopenharmony_ci		if (connection_broken(vscsi))
15838c2ecf20Sopenharmony_ci			flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
15848c2ecf20Sopenharmony_ci		fallthrough;
15858c2ecf20Sopenharmony_ci	default:
15868c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "adapter_info: h_copy_rdma to client failed, rc %ld\n",
15878c2ecf20Sopenharmony_ci			rc);
15888c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi,
15898c2ecf20Sopenharmony_ci					  ERR_DISCONNECT_RECONNECT,
15908c2ecf20Sopenharmony_ci					  flag_bits);
15918c2ecf20Sopenharmony_ci		break;
15928c2ecf20Sopenharmony_ci	}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_cifree_dma:
15958c2ecf20Sopenharmony_ci	dma_free_coherent(&vscsi->dma_dev->dev, sizeof(*info), info, token);
15968c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving adapter_info, rc %ld\n", rc);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	return rc;
15998c2ecf20Sopenharmony_ci}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci/**
16028c2ecf20Sopenharmony_ci * ibmvscsis_cap_mad() - Service a Capabilities MAnagement Data gram
16038c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
16048c2ecf20Sopenharmony_ci * @iue:	Information Unit containing the Capabilities MAD request
16058c2ecf20Sopenharmony_ci *
16068c2ecf20Sopenharmony_ci * NOTE: if you return an error from this routine you must be
16078c2ecf20Sopenharmony_ci * disconnecting or you will cause a hang
16088c2ecf20Sopenharmony_ci *
16098c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
16108c2ecf20Sopenharmony_ci *	Interrupt called with adapter lock held
16118c2ecf20Sopenharmony_ci */
16128c2ecf20Sopenharmony_cistatic int ibmvscsis_cap_mad(struct scsi_info *vscsi, struct iu_entry *iue)
16138c2ecf20Sopenharmony_ci{
16148c2ecf20Sopenharmony_ci	struct viosrp_capabilities *mad = &vio_iu(iue)->mad.capabilities;
16158c2ecf20Sopenharmony_ci	struct capabilities *cap;
16168c2ecf20Sopenharmony_ci	struct mad_capability_common *common;
16178c2ecf20Sopenharmony_ci	dma_addr_t token;
16188c2ecf20Sopenharmony_ci	u16 olen, len, status, min_len, cap_len;
16198c2ecf20Sopenharmony_ci	u32 flag;
16208c2ecf20Sopenharmony_ci	uint flag_bits = 0;
16218c2ecf20Sopenharmony_ci	long rc = 0;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	olen = be16_to_cpu(mad->common.length);
16248c2ecf20Sopenharmony_ci	/*
16258c2ecf20Sopenharmony_ci	 * struct capabilities hardcodes a couple capabilities after the
16268c2ecf20Sopenharmony_ci	 * header, but the capabilities can actually be in any order.
16278c2ecf20Sopenharmony_ci	 */
16288c2ecf20Sopenharmony_ci	min_len = offsetof(struct capabilities, migration);
16298c2ecf20Sopenharmony_ci	if ((olen < min_len) || (olen > PAGE_SIZE)) {
16308c2ecf20Sopenharmony_ci		dev_warn(&vscsi->dev, "cap_mad: invalid len %d\n", olen);
16318c2ecf20Sopenharmony_ci		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
16328c2ecf20Sopenharmony_ci		return 0;
16338c2ecf20Sopenharmony_ci	}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token,
16368c2ecf20Sopenharmony_ci				 GFP_ATOMIC);
16378c2ecf20Sopenharmony_ci	if (!cap) {
16388c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
16398c2ecf20Sopenharmony_ci			iue->target);
16408c2ecf20Sopenharmony_ci		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
16418c2ecf20Sopenharmony_ci		return 0;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci	rc = h_copy_rdma(olen, vscsi->dds.window[REMOTE].liobn,
16448c2ecf20Sopenharmony_ci			 be64_to_cpu(mad->buffer),
16458c2ecf20Sopenharmony_ci			 vscsi->dds.window[LOCAL].liobn, token);
16468c2ecf20Sopenharmony_ci	if (rc == H_SUCCESS) {
16478c2ecf20Sopenharmony_ci		strncpy(cap->name, dev_name(&vscsi->dma_dev->dev),
16488c2ecf20Sopenharmony_ci			SRP_MAX_LOC_LEN);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci		len = olen - min_len;
16518c2ecf20Sopenharmony_ci		status = VIOSRP_MAD_SUCCESS;
16528c2ecf20Sopenharmony_ci		common = (struct mad_capability_common *)&cap->migration;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		while ((len > 0) && (status == VIOSRP_MAD_SUCCESS) && !rc) {
16558c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "cap_mad: len left %hd, cap type %d, cap len %hd\n",
16568c2ecf20Sopenharmony_ci				len, be32_to_cpu(common->cap_type),
16578c2ecf20Sopenharmony_ci				be16_to_cpu(common->length));
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci			cap_len = be16_to_cpu(common->length);
16608c2ecf20Sopenharmony_ci			if (cap_len > len) {
16618c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "cap_mad: cap len mismatch with total len\n");
16628c2ecf20Sopenharmony_ci				status = VIOSRP_MAD_FAILED;
16638c2ecf20Sopenharmony_ci				break;
16648c2ecf20Sopenharmony_ci			}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci			if (cap_len == 0) {
16678c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "cap_mad: cap len is 0\n");
16688c2ecf20Sopenharmony_ci				status = VIOSRP_MAD_FAILED;
16698c2ecf20Sopenharmony_ci				break;
16708c2ecf20Sopenharmony_ci			}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci			switch (common->cap_type) {
16738c2ecf20Sopenharmony_ci			default:
16748c2ecf20Sopenharmony_ci				dev_dbg(&vscsi->dev, "cap_mad: unsupported capability\n");
16758c2ecf20Sopenharmony_ci				common->server_support = 0;
16768c2ecf20Sopenharmony_ci				flag = cpu_to_be32((u32)CAP_LIST_SUPPORTED);
16778c2ecf20Sopenharmony_ci				cap->flags &= ~flag;
16788c2ecf20Sopenharmony_ci				break;
16798c2ecf20Sopenharmony_ci			}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci			len = len - cap_len;
16828c2ecf20Sopenharmony_ci			common = (struct mad_capability_common *)
16838c2ecf20Sopenharmony_ci				((char *)common + cap_len);
16848c2ecf20Sopenharmony_ci		}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci		mad->common.status = cpu_to_be16(status);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci		dma_wmb();
16898c2ecf20Sopenharmony_ci		rc = h_copy_rdma(olen, vscsi->dds.window[LOCAL].liobn, token,
16908c2ecf20Sopenharmony_ci				 vscsi->dds.window[REMOTE].liobn,
16918c2ecf20Sopenharmony_ci				 be64_to_cpu(mad->buffer));
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci		if (rc != H_SUCCESS) {
16948c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "cap_mad: failed to copy to client, rc %ld\n",
16958c2ecf20Sopenharmony_ci				rc);
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci			if (rc == H_PERMISSION) {
16988c2ecf20Sopenharmony_ci				if (connection_broken(vscsi))
16998c2ecf20Sopenharmony_ci					flag_bits = (RESPONSE_Q_DOWN |
17008c2ecf20Sopenharmony_ci						     CLIENT_FAILED);
17018c2ecf20Sopenharmony_ci			}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci			dev_warn(&vscsi->dev, "cap_mad: error copying data to client, rc %ld\n",
17048c2ecf20Sopenharmony_ci				 rc);
17058c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
17068c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT,
17078c2ecf20Sopenharmony_ci						  flag_bits);
17088c2ecf20Sopenharmony_ci		}
17098c2ecf20Sopenharmony_ci	}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	dma_free_coherent(&vscsi->dma_dev->dev, olen, cap, token);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving cap_mad, rc %ld, client_cap 0x%x\n",
17148c2ecf20Sopenharmony_ci		rc, vscsi->client_cap);
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	return rc;
17178c2ecf20Sopenharmony_ci}
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci/**
17208c2ecf20Sopenharmony_ci * ibmvscsis_process_mad() - Service a MAnagement Data gram
17218c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
17228c2ecf20Sopenharmony_ci * @iue:	Information Unit containing the MAD request
17238c2ecf20Sopenharmony_ci *
17248c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
17258c2ecf20Sopenharmony_ci */
17268c2ecf20Sopenharmony_cistatic long ibmvscsis_process_mad(struct scsi_info *vscsi, struct iu_entry *iue)
17278c2ecf20Sopenharmony_ci{
17288c2ecf20Sopenharmony_ci	struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
17298c2ecf20Sopenharmony_ci	struct viosrp_empty_iu *empty;
17308c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	switch (be32_to_cpu(mad->type)) {
17338c2ecf20Sopenharmony_ci	case VIOSRP_EMPTY_IU_TYPE:
17348c2ecf20Sopenharmony_ci		empty = &vio_iu(iue)->mad.empty_iu;
17358c2ecf20Sopenharmony_ci		vscsi->empty_iu_id = be64_to_cpu(empty->buffer);
17368c2ecf20Sopenharmony_ci		vscsi->empty_iu_tag = be64_to_cpu(empty->common.tag);
17378c2ecf20Sopenharmony_ci		mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
17388c2ecf20Sopenharmony_ci		break;
17398c2ecf20Sopenharmony_ci	case VIOSRP_ADAPTER_INFO_TYPE:
17408c2ecf20Sopenharmony_ci		rc = ibmvscsis_adapter_info(vscsi, iue);
17418c2ecf20Sopenharmony_ci		break;
17428c2ecf20Sopenharmony_ci	case VIOSRP_CAPABILITIES_TYPE:
17438c2ecf20Sopenharmony_ci		rc = ibmvscsis_cap_mad(vscsi, iue);
17448c2ecf20Sopenharmony_ci		break;
17458c2ecf20Sopenharmony_ci	case VIOSRP_ENABLE_FAST_FAIL:
17468c2ecf20Sopenharmony_ci		if (vscsi->state == CONNECTED) {
17478c2ecf20Sopenharmony_ci			vscsi->fast_fail = true;
17488c2ecf20Sopenharmony_ci			mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
17498c2ecf20Sopenharmony_ci		} else {
17508c2ecf20Sopenharmony_ci			dev_warn(&vscsi->dev, "fast fail mad sent after login\n");
17518c2ecf20Sopenharmony_ci			mad->status = cpu_to_be16(VIOSRP_MAD_FAILED);
17528c2ecf20Sopenharmony_ci		}
17538c2ecf20Sopenharmony_ci		break;
17548c2ecf20Sopenharmony_ci	default:
17558c2ecf20Sopenharmony_ci		mad->status = cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
17568c2ecf20Sopenharmony_ci		break;
17578c2ecf20Sopenharmony_ci	}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	return rc;
17608c2ecf20Sopenharmony_ci}
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci/**
17638c2ecf20Sopenharmony_ci * srp_snd_msg_failed() - Handle an error when sending a response
17648c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
17658c2ecf20Sopenharmony_ci * @rc:		The return code from the h_send_crq command
17668c2ecf20Sopenharmony_ci *
17678c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
17688c2ecf20Sopenharmony_ci */
17698c2ecf20Sopenharmony_cistatic void srp_snd_msg_failed(struct scsi_info *vscsi, long rc)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	ktime_t kt;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	if (rc != H_DROPPED) {
17748c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_qs(vscsi);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci		if (rc == H_CLOSED)
17778c2ecf20Sopenharmony_ci			vscsi->flags |= CLIENT_FAILED;
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci		/* don't flag the same problem multiple times */
17808c2ecf20Sopenharmony_ci		if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
17818c2ecf20Sopenharmony_ci			vscsi->flags |= RESPONSE_Q_DOWN;
17828c2ecf20Sopenharmony_ci			if (!(vscsi->state & (ERR_DISCONNECT |
17838c2ecf20Sopenharmony_ci					      ERR_DISCONNECT_RECONNECT |
17848c2ecf20Sopenharmony_ci					      ERR_DISCONNECTED | UNDEFINED))) {
17858c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "snd_msg_failed: setting RESPONSE_Q_DOWN, state 0x%hx, flags 0x%x, rc %ld\n",
17868c2ecf20Sopenharmony_ci					vscsi->state, vscsi->flags, rc);
17878c2ecf20Sopenharmony_ci			}
17888c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
17898c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
17908c2ecf20Sopenharmony_ci		}
17918c2ecf20Sopenharmony_ci		return;
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	/*
17958c2ecf20Sopenharmony_ci	 * The response queue is full.
17968c2ecf20Sopenharmony_ci	 * If the server is processing SRP requests, i.e.
17978c2ecf20Sopenharmony_ci	 * the client has successfully done an
17988c2ecf20Sopenharmony_ci	 * SRP_LOGIN, then it will wait forever for room in
17998c2ecf20Sopenharmony_ci	 * the queue.  However if the system admin
18008c2ecf20Sopenharmony_ci	 * is attempting to unconfigure the server then one
18018c2ecf20Sopenharmony_ci	 * or more children will be in a state where
18028c2ecf20Sopenharmony_ci	 * they are being removed. So if there is even one
18038c2ecf20Sopenharmony_ci	 * child being removed then the driver assumes
18048c2ecf20Sopenharmony_ci	 * the system admin is attempting to break the
18058c2ecf20Sopenharmony_ci	 * connection with the client and MAX_TIMER_POPS
18068c2ecf20Sopenharmony_ci	 * is honored.
18078c2ecf20Sopenharmony_ci	 */
18088c2ecf20Sopenharmony_ci	if ((vscsi->rsp_q_timer.timer_pops < MAX_TIMER_POPS) ||
18098c2ecf20Sopenharmony_ci	    (vscsi->state == SRP_PROCESSING)) {
18108c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "snd_msg_failed: response queue full, flags 0x%x, timer started %d, pops %d\n",
18118c2ecf20Sopenharmony_ci			vscsi->flags, (int)vscsi->rsp_q_timer.started,
18128c2ecf20Sopenharmony_ci			vscsi->rsp_q_timer.timer_pops);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci		/*
18158c2ecf20Sopenharmony_ci		 * Check if the timer is running; if it
18168c2ecf20Sopenharmony_ci		 * is not then start it up.
18178c2ecf20Sopenharmony_ci		 */
18188c2ecf20Sopenharmony_ci		if (!vscsi->rsp_q_timer.started) {
18198c2ecf20Sopenharmony_ci			if (vscsi->rsp_q_timer.timer_pops <
18208c2ecf20Sopenharmony_ci			    MAX_TIMER_POPS) {
18218c2ecf20Sopenharmony_ci				kt = WAIT_NANO_SECONDS;
18228c2ecf20Sopenharmony_ci			} else {
18238c2ecf20Sopenharmony_ci				/*
18248c2ecf20Sopenharmony_ci				 * slide the timeslice if the maximum
18258c2ecf20Sopenharmony_ci				 * timer pops have already happened
18268c2ecf20Sopenharmony_ci				 */
18278c2ecf20Sopenharmony_ci				kt = ktime_set(WAIT_SECONDS, 0);
18288c2ecf20Sopenharmony_ci			}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci			vscsi->rsp_q_timer.started = true;
18318c2ecf20Sopenharmony_ci			hrtimer_start(&vscsi->rsp_q_timer.timer, kt,
18328c2ecf20Sopenharmony_ci				      HRTIMER_MODE_REL);
18338c2ecf20Sopenharmony_ci		}
18348c2ecf20Sopenharmony_ci	} else {
18358c2ecf20Sopenharmony_ci		/*
18368c2ecf20Sopenharmony_ci		 * TBD: Do we need to worry about this? Need to get
18378c2ecf20Sopenharmony_ci		 *      remove working.
18388c2ecf20Sopenharmony_ci		 */
18398c2ecf20Sopenharmony_ci		/*
18408c2ecf20Sopenharmony_ci		 * waited a long time and it appears the system admin
18418c2ecf20Sopenharmony_ci		 * is bring this driver down
18428c2ecf20Sopenharmony_ci		 */
18438c2ecf20Sopenharmony_ci		vscsi->flags |= RESPONSE_Q_DOWN;
18448c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_qs(vscsi);
18458c2ecf20Sopenharmony_ci		/*
18468c2ecf20Sopenharmony_ci		 * if the driver is already attempting to disconnect
18478c2ecf20Sopenharmony_ci		 * from the client and has already logged an error
18488c2ecf20Sopenharmony_ci		 * trace this event but don't put it in the error log
18498c2ecf20Sopenharmony_ci		 */
18508c2ecf20Sopenharmony_ci		if (!(vscsi->state & (ERR_DISCONNECT |
18518c2ecf20Sopenharmony_ci				      ERR_DISCONNECT_RECONNECT |
18528c2ecf20Sopenharmony_ci				      ERR_DISCONNECTED | UNDEFINED))) {
18538c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "client crq full too long\n");
18548c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
18558c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT,
18568c2ecf20Sopenharmony_ci						  0);
18578c2ecf20Sopenharmony_ci		}
18588c2ecf20Sopenharmony_ci	}
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci/**
18628c2ecf20Sopenharmony_ci * ibmvscsis_send_messages() - Send a Response
18638c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
18648c2ecf20Sopenharmony_ci *
18658c2ecf20Sopenharmony_ci * Send a response, first checking the waiting queue. Responses are
18668c2ecf20Sopenharmony_ci * sent in order they are received. If the response cannot be sent,
18678c2ecf20Sopenharmony_ci * because the client queue is full, it stays on the waiting queue.
18688c2ecf20Sopenharmony_ci *
18698c2ecf20Sopenharmony_ci * PRECONDITION:
18708c2ecf20Sopenharmony_ci *	Called with interrupt lock held
18718c2ecf20Sopenharmony_ci */
18728c2ecf20Sopenharmony_cistatic void ibmvscsis_send_messages(struct scsi_info *vscsi)
18738c2ecf20Sopenharmony_ci{
18748c2ecf20Sopenharmony_ci	u64 msg_hi = 0;
18758c2ecf20Sopenharmony_ci	/* note do not attempt to access the IU_data_ptr with this pointer
18768c2ecf20Sopenharmony_ci	 * it is not valid
18778c2ecf20Sopenharmony_ci	 */
18788c2ecf20Sopenharmony_ci	struct viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
18798c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd, *nxt;
18808c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
18818c2ecf20Sopenharmony_ci	bool retry = false;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
18848c2ecf20Sopenharmony_ci		do {
18858c2ecf20Sopenharmony_ci			retry = false;
18868c2ecf20Sopenharmony_ci			list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp,
18878c2ecf20Sopenharmony_ci						 list) {
18888c2ecf20Sopenharmony_ci				/*
18898c2ecf20Sopenharmony_ci				 * Check to make sure abort cmd gets processed
18908c2ecf20Sopenharmony_ci				 * prior to the abort tmr cmd
18918c2ecf20Sopenharmony_ci				 */
18928c2ecf20Sopenharmony_ci				if (cmd->flags & DELAY_SEND)
18938c2ecf20Sopenharmony_ci					continue;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci				if (cmd->abort_cmd) {
18968c2ecf20Sopenharmony_ci					retry = true;
18978c2ecf20Sopenharmony_ci					cmd->abort_cmd->flags &= ~(DELAY_SEND);
18988c2ecf20Sopenharmony_ci					cmd->abort_cmd = NULL;
18998c2ecf20Sopenharmony_ci				}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci				/*
19028c2ecf20Sopenharmony_ci				 * If CMD_T_ABORTED w/o CMD_T_TAS scenarios and
19038c2ecf20Sopenharmony_ci				 * the case where LIO issued a
19048c2ecf20Sopenharmony_ci				 * ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST
19058c2ecf20Sopenharmony_ci				 * case then we dont send a response, since it
19068c2ecf20Sopenharmony_ci				 * was already done.
19078c2ecf20Sopenharmony_ci				 */
19088c2ecf20Sopenharmony_ci				if (cmd->se_cmd.transport_state & CMD_T_ABORTED &&
19098c2ecf20Sopenharmony_ci				    !(cmd->se_cmd.transport_state & CMD_T_TAS)) {
19108c2ecf20Sopenharmony_ci					list_del(&cmd->list);
19118c2ecf20Sopenharmony_ci					ibmvscsis_free_cmd_resources(vscsi,
19128c2ecf20Sopenharmony_ci								     cmd);
19138c2ecf20Sopenharmony_ci					/*
19148c2ecf20Sopenharmony_ci					 * With a successfully aborted op
19158c2ecf20Sopenharmony_ci					 * through LIO we want to increment the
19168c2ecf20Sopenharmony_ci					 * the vscsi credit so that when we dont
19178c2ecf20Sopenharmony_ci					 * send a rsp to the original scsi abort
19188c2ecf20Sopenharmony_ci					 * op (h_send_crq), but the tm rsp to
19198c2ecf20Sopenharmony_ci					 * the abort is sent, the credit is
19208c2ecf20Sopenharmony_ci					 * correctly sent with the abort tm rsp.
19218c2ecf20Sopenharmony_ci					 * We would need 1 for the abort tm rsp
19228c2ecf20Sopenharmony_ci					 * and 1 credit for the aborted scsi op.
19238c2ecf20Sopenharmony_ci					 * Thus we need to increment here.
19248c2ecf20Sopenharmony_ci					 * Also we want to increment the credit
19258c2ecf20Sopenharmony_ci					 * here because we want to make sure
19268c2ecf20Sopenharmony_ci					 * cmd is actually released first
19278c2ecf20Sopenharmony_ci					 * otherwise the client will think it
19288c2ecf20Sopenharmony_ci					 * it can send a new cmd, and we could
19298c2ecf20Sopenharmony_ci					 * find ourselves short of cmd elements.
19308c2ecf20Sopenharmony_ci					 */
19318c2ecf20Sopenharmony_ci					vscsi->credit += 1;
19328c2ecf20Sopenharmony_ci				} else {
19338c2ecf20Sopenharmony_ci					crq->valid = VALID_CMD_RESP_EL;
19348c2ecf20Sopenharmony_ci					crq->format = cmd->rsp.format;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci					if (cmd->flags & CMD_FAST_FAIL)
19378c2ecf20Sopenharmony_ci						crq->status = VIOSRP_ADAPTER_FAIL;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci					crq->IU_length = cpu_to_be16(cmd->rsp.len);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci					rc = h_send_crq(vscsi->dma_dev->unit_address,
19428c2ecf20Sopenharmony_ci							be64_to_cpu(msg_hi),
19438c2ecf20Sopenharmony_ci							be64_to_cpu(cmd->rsp.tag));
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci					dev_dbg(&vscsi->dev, "send_messages: cmd %p, tag 0x%llx, rc %ld\n",
19468c2ecf20Sopenharmony_ci						cmd, be64_to_cpu(cmd->rsp.tag),
19478c2ecf20Sopenharmony_ci						rc);
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci					/* if all ok free up the command
19508c2ecf20Sopenharmony_ci					 * element resources
19518c2ecf20Sopenharmony_ci					 */
19528c2ecf20Sopenharmony_ci					if (rc == H_SUCCESS) {
19538c2ecf20Sopenharmony_ci						/* some movement has occurred */
19548c2ecf20Sopenharmony_ci						vscsi->rsp_q_timer.timer_pops = 0;
19558c2ecf20Sopenharmony_ci						list_del(&cmd->list);
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci						ibmvscsis_free_cmd_resources(vscsi,
19588c2ecf20Sopenharmony_ci									     cmd);
19598c2ecf20Sopenharmony_ci					} else {
19608c2ecf20Sopenharmony_ci						srp_snd_msg_failed(vscsi, rc);
19618c2ecf20Sopenharmony_ci						break;
19628c2ecf20Sopenharmony_ci					}
19638c2ecf20Sopenharmony_ci				}
19648c2ecf20Sopenharmony_ci			}
19658c2ecf20Sopenharmony_ci		} while (retry);
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci		if (!rc) {
19688c2ecf20Sopenharmony_ci			/*
19698c2ecf20Sopenharmony_ci			 * The timer could pop with the queue empty.  If
19708c2ecf20Sopenharmony_ci			 * this happens, rc will always indicate a
19718c2ecf20Sopenharmony_ci			 * success; clear the pop count.
19728c2ecf20Sopenharmony_ci			 */
19738c2ecf20Sopenharmony_ci			vscsi->rsp_q_timer.timer_pops = 0;
19748c2ecf20Sopenharmony_ci		}
19758c2ecf20Sopenharmony_ci	} else {
19768c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_qs(vscsi);
19778c2ecf20Sopenharmony_ci	}
19788c2ecf20Sopenharmony_ci}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci/* Called with intr lock held */
19818c2ecf20Sopenharmony_cistatic void ibmvscsis_send_mad_resp(struct scsi_info *vscsi,
19828c2ecf20Sopenharmony_ci				    struct ibmvscsis_cmd *cmd,
19838c2ecf20Sopenharmony_ci				    struct viosrp_crq *crq)
19848c2ecf20Sopenharmony_ci{
19858c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
19868c2ecf20Sopenharmony_ci	struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
19878c2ecf20Sopenharmony_ci	uint flag_bits = 0;
19888c2ecf20Sopenharmony_ci	long rc;
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	dma_wmb();
19918c2ecf20Sopenharmony_ci	rc = h_copy_rdma(sizeof(struct mad_common),
19928c2ecf20Sopenharmony_ci			 vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
19938c2ecf20Sopenharmony_ci			 vscsi->dds.window[REMOTE].liobn,
19948c2ecf20Sopenharmony_ci			 be64_to_cpu(crq->IU_data_ptr));
19958c2ecf20Sopenharmony_ci	if (!rc) {
19968c2ecf20Sopenharmony_ci		cmd->rsp.format = VIOSRP_MAD_FORMAT;
19978c2ecf20Sopenharmony_ci		cmd->rsp.len = sizeof(struct mad_common);
19988c2ecf20Sopenharmony_ci		cmd->rsp.tag = mad->tag;
19998c2ecf20Sopenharmony_ci		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
20008c2ecf20Sopenharmony_ci		ibmvscsis_send_messages(vscsi);
20018c2ecf20Sopenharmony_ci	} else {
20028c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "Error sending mad response, rc %ld\n",
20038c2ecf20Sopenharmony_ci			rc);
20048c2ecf20Sopenharmony_ci		if (rc == H_PERMISSION) {
20058c2ecf20Sopenharmony_ci			if (connection_broken(vscsi))
20068c2ecf20Sopenharmony_ci				flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
20078c2ecf20Sopenharmony_ci		}
20088c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "mad: failed to copy to client, rc %ld\n",
20098c2ecf20Sopenharmony_ci			rc);
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
20128c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
20138c2ecf20Sopenharmony_ci					  flag_bits);
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci/**
20188c2ecf20Sopenharmony_ci * ibmvscsis_mad() - Service a MAnagement Data gram.
20198c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
20208c2ecf20Sopenharmony_ci * @crq:	Pointer to the CRQ entry containing the MAD request
20218c2ecf20Sopenharmony_ci *
20228c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
20238c2ecf20Sopenharmony_ci *	Interrupt, called with adapter lock held
20248c2ecf20Sopenharmony_ci */
20258c2ecf20Sopenharmony_cistatic long ibmvscsis_mad(struct scsi_info *vscsi, struct viosrp_crq *crq)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	struct iu_entry *iue;
20288c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd;
20298c2ecf20Sopenharmony_ci	struct mad_common *mad;
20308c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	switch (vscsi->state) {
20338c2ecf20Sopenharmony_ci		/*
20348c2ecf20Sopenharmony_ci		 * We have not exchanged Init Msgs yet, so this MAD was sent
20358c2ecf20Sopenharmony_ci		 * before the last Transport Event; client will not be
20368c2ecf20Sopenharmony_ci		 * expecting a response.
20378c2ecf20Sopenharmony_ci		 */
20388c2ecf20Sopenharmony_ci	case WAIT_CONNECTION:
20398c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "mad: in Wait Connection state, ignoring MAD, flags %d\n",
20408c2ecf20Sopenharmony_ci			vscsi->flags);
20418c2ecf20Sopenharmony_ci		return ADAPT_SUCCESS;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	case SRP_PROCESSING:
20448c2ecf20Sopenharmony_ci	case CONNECTED:
20458c2ecf20Sopenharmony_ci		break;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		/*
20488c2ecf20Sopenharmony_ci		 * We should never get here while we're in these states.
20498c2ecf20Sopenharmony_ci		 * Just log an error and get out.
20508c2ecf20Sopenharmony_ci		 */
20518c2ecf20Sopenharmony_ci	case UNCONFIGURING:
20528c2ecf20Sopenharmony_ci	case WAIT_IDLE:
20538c2ecf20Sopenharmony_ci	case ERR_DISCONNECT:
20548c2ecf20Sopenharmony_ci	case ERR_DISCONNECT_RECONNECT:
20558c2ecf20Sopenharmony_ci	default:
20568c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "mad: invalid adapter state %d for mad\n",
20578c2ecf20Sopenharmony_ci			vscsi->state);
20588c2ecf20Sopenharmony_ci		return ADAPT_SUCCESS;
20598c2ecf20Sopenharmony_ci	}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	cmd = ibmvscsis_get_free_cmd(vscsi);
20628c2ecf20Sopenharmony_ci	if (!cmd) {
20638c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "mad: failed to get cmd, debit %d\n",
20648c2ecf20Sopenharmony_ci			vscsi->debit);
20658c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
20668c2ecf20Sopenharmony_ci		return ERROR;
20678c2ecf20Sopenharmony_ci	}
20688c2ecf20Sopenharmony_ci	iue = cmd->iue;
20698c2ecf20Sopenharmony_ci	cmd->type = ADAPTER_MAD;
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
20728c2ecf20Sopenharmony_ci	if (!rc) {
20738c2ecf20Sopenharmony_ci		mad = (struct mad_common *)&vio_iu(iue)->mad;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "mad: type %d\n", be32_to_cpu(mad->type));
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		rc = ibmvscsis_process_mad(vscsi, iue);
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "mad: status %hd, rc %ld\n",
20808c2ecf20Sopenharmony_ci			be16_to_cpu(mad->status), rc);
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci		if (!rc)
20838c2ecf20Sopenharmony_ci			ibmvscsis_send_mad_resp(vscsi, cmd, crq);
20848c2ecf20Sopenharmony_ci	} else {
20858c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
20868c2ecf20Sopenharmony_ci	}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving mad, rc %ld\n", rc);
20898c2ecf20Sopenharmony_ci	return rc;
20908c2ecf20Sopenharmony_ci}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci/**
20938c2ecf20Sopenharmony_ci * ibmvscsis_login_rsp() - Create/copy a login response notice to the client
20948c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
20958c2ecf20Sopenharmony_ci * @cmd:	Pointer to the command for the SRP Login request
20968c2ecf20Sopenharmony_ci *
20978c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
20988c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
20998c2ecf20Sopenharmony_ci */
21008c2ecf20Sopenharmony_cistatic long ibmvscsis_login_rsp(struct scsi_info *vscsi,
21018c2ecf20Sopenharmony_ci				struct ibmvscsis_cmd *cmd)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
21048c2ecf20Sopenharmony_ci	struct srp_login_rsp *rsp = &vio_iu(iue)->srp.login_rsp;
21058c2ecf20Sopenharmony_ci	struct format_code *fmt;
21068c2ecf20Sopenharmony_ci	uint flag_bits = 0;
21078c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	memset(rsp, 0, sizeof(struct srp_login_rsp));
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	rsp->opcode = SRP_LOGIN_RSP;
21128c2ecf20Sopenharmony_ci	rsp->req_lim_delta = cpu_to_be32(vscsi->request_limit);
21138c2ecf20Sopenharmony_ci	rsp->tag = cmd->rsp.tag;
21148c2ecf20Sopenharmony_ci	rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
21158c2ecf20Sopenharmony_ci	rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
21168c2ecf20Sopenharmony_ci	fmt = (struct format_code *)&rsp->buf_fmt;
21178c2ecf20Sopenharmony_ci	fmt->buffers = SUPPORTED_FORMATS;
21188c2ecf20Sopenharmony_ci	vscsi->credit = 0;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	cmd->rsp.len = sizeof(struct srp_login_rsp);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	dma_wmb();
21238c2ecf20Sopenharmony_ci	rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
21248c2ecf20Sopenharmony_ci			 iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
21258c2ecf20Sopenharmony_ci			 be64_to_cpu(iue->remote_token));
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	switch (rc) {
21288c2ecf20Sopenharmony_ci	case H_SUCCESS:
21298c2ecf20Sopenharmony_ci		break;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	case H_PERMISSION:
21328c2ecf20Sopenharmony_ci		if (connection_broken(vscsi))
21338c2ecf20Sopenharmony_ci			flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
21348c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
21358c2ecf20Sopenharmony_ci			rc);
21368c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
21378c2ecf20Sopenharmony_ci					  flag_bits);
21388c2ecf20Sopenharmony_ci		break;
21398c2ecf20Sopenharmony_ci	case H_SOURCE_PARM:
21408c2ecf20Sopenharmony_ci	case H_DEST_PARM:
21418c2ecf20Sopenharmony_ci	default:
21428c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
21438c2ecf20Sopenharmony_ci			rc);
21448c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
21458c2ecf20Sopenharmony_ci		break;
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	return rc;
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci/**
21528c2ecf20Sopenharmony_ci * ibmvscsis_srp_login_rej() - Create/copy a login rejection notice to client
21538c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
21548c2ecf20Sopenharmony_ci * @cmd:	Pointer to the command for the SRP Login request
21558c2ecf20Sopenharmony_ci * @reason:	The reason the SRP Login is being rejected, per SRP protocol
21568c2ecf20Sopenharmony_ci *
21578c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
21588c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
21598c2ecf20Sopenharmony_ci */
21608c2ecf20Sopenharmony_cistatic long ibmvscsis_srp_login_rej(struct scsi_info *vscsi,
21618c2ecf20Sopenharmony_ci				    struct ibmvscsis_cmd *cmd, u32 reason)
21628c2ecf20Sopenharmony_ci{
21638c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
21648c2ecf20Sopenharmony_ci	struct srp_login_rej *rej = &vio_iu(iue)->srp.login_rej;
21658c2ecf20Sopenharmony_ci	struct format_code *fmt;
21668c2ecf20Sopenharmony_ci	uint flag_bits = 0;
21678c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	memset(rej, 0, sizeof(*rej));
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	rej->opcode = SRP_LOGIN_REJ;
21728c2ecf20Sopenharmony_ci	rej->reason = cpu_to_be32(reason);
21738c2ecf20Sopenharmony_ci	rej->tag = cmd->rsp.tag;
21748c2ecf20Sopenharmony_ci	fmt = (struct format_code *)&rej->buf_fmt;
21758c2ecf20Sopenharmony_ci	fmt->buffers = SUPPORTED_FORMATS;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	cmd->rsp.len = sizeof(*rej);
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	dma_wmb();
21808c2ecf20Sopenharmony_ci	rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
21818c2ecf20Sopenharmony_ci			 iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
21828c2ecf20Sopenharmony_ci			 be64_to_cpu(iue->remote_token));
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	switch (rc) {
21858c2ecf20Sopenharmony_ci	case H_SUCCESS:
21868c2ecf20Sopenharmony_ci		break;
21878c2ecf20Sopenharmony_ci	case H_PERMISSION:
21888c2ecf20Sopenharmony_ci		if (connection_broken(vscsi))
21898c2ecf20Sopenharmony_ci			flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
21908c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
21918c2ecf20Sopenharmony_ci			rc);
21928c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
21938c2ecf20Sopenharmony_ci					  flag_bits);
21948c2ecf20Sopenharmony_ci		break;
21958c2ecf20Sopenharmony_ci	case H_SOURCE_PARM:
21968c2ecf20Sopenharmony_ci	case H_DEST_PARM:
21978c2ecf20Sopenharmony_ci	default:
21988c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
21998c2ecf20Sopenharmony_ci			rc);
22008c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
22018c2ecf20Sopenharmony_ci		break;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	return rc;
22058c2ecf20Sopenharmony_ci}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_cistatic int ibmvscsis_make_nexus(struct ibmvscsis_tport *tport)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci	char *name = tport->tport_name;
22108c2ecf20Sopenharmony_ci	struct ibmvscsis_nexus *nexus;
22118c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport);
22128c2ecf20Sopenharmony_ci	int rc;
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	if (tport->ibmv_nexus) {
22158c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "tport->ibmv_nexus already exists\n");
22168c2ecf20Sopenharmony_ci		return 0;
22178c2ecf20Sopenharmony_ci	}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	nexus = kzalloc(sizeof(*nexus), GFP_KERNEL);
22208c2ecf20Sopenharmony_ci	if (!nexus) {
22218c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Unable to allocate struct ibmvscsis_nexus\n");
22228c2ecf20Sopenharmony_ci		return -ENOMEM;
22238c2ecf20Sopenharmony_ci	}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	nexus->se_sess = target_setup_session(&tport->se_tpg, 0, 0,
22268c2ecf20Sopenharmony_ci					      TARGET_PROT_NORMAL, name, nexus,
22278c2ecf20Sopenharmony_ci					      NULL);
22288c2ecf20Sopenharmony_ci	if (IS_ERR(nexus->se_sess)) {
22298c2ecf20Sopenharmony_ci		rc = PTR_ERR(nexus->se_sess);
22308c2ecf20Sopenharmony_ci		goto transport_init_fail;
22318c2ecf20Sopenharmony_ci	}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	tport->ibmv_nexus = nexus;
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	return 0;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_citransport_init_fail:
22388c2ecf20Sopenharmony_ci	kfree(nexus);
22398c2ecf20Sopenharmony_ci	return rc;
22408c2ecf20Sopenharmony_ci}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_cistatic int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
22438c2ecf20Sopenharmony_ci{
22448c2ecf20Sopenharmony_ci	struct se_session *se_sess;
22458c2ecf20Sopenharmony_ci	struct ibmvscsis_nexus *nexus;
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	nexus = tport->ibmv_nexus;
22488c2ecf20Sopenharmony_ci	if (!nexus)
22498c2ecf20Sopenharmony_ci		return -ENODEV;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	se_sess = nexus->se_sess;
22528c2ecf20Sopenharmony_ci	if (!se_sess)
22538c2ecf20Sopenharmony_ci		return -ENODEV;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	/*
22568c2ecf20Sopenharmony_ci	 * Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port
22578c2ecf20Sopenharmony_ci	 */
22588c2ecf20Sopenharmony_ci	target_remove_session(se_sess);
22598c2ecf20Sopenharmony_ci	tport->ibmv_nexus = NULL;
22608c2ecf20Sopenharmony_ci	kfree(nexus);
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	return 0;
22638c2ecf20Sopenharmony_ci}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci/**
22668c2ecf20Sopenharmony_ci * ibmvscsis_srp_login() - Process an SRP Login Request
22678c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
22688c2ecf20Sopenharmony_ci * @cmd:	Command element to use to process the SRP Login request
22698c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ entry containing the SRP Login request
22708c2ecf20Sopenharmony_ci *
22718c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
22728c2ecf20Sopenharmony_ci *	Interrupt, called with interrupt lock held
22738c2ecf20Sopenharmony_ci */
22748c2ecf20Sopenharmony_cistatic long ibmvscsis_srp_login(struct scsi_info *vscsi,
22758c2ecf20Sopenharmony_ci				struct ibmvscsis_cmd *cmd,
22768c2ecf20Sopenharmony_ci				struct viosrp_crq *crq)
22778c2ecf20Sopenharmony_ci{
22788c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
22798c2ecf20Sopenharmony_ci	struct srp_login_req *req = &vio_iu(iue)->srp.login_req;
22808c2ecf20Sopenharmony_ci	struct port_id {
22818c2ecf20Sopenharmony_ci		__be64 id_extension;
22828c2ecf20Sopenharmony_ci		__be64 io_guid;
22838c2ecf20Sopenharmony_ci	} *iport, *tport;
22848c2ecf20Sopenharmony_ci	struct format_code *fmt;
22858c2ecf20Sopenharmony_ci	u32 reason = 0x0;
22868c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	iport = (struct port_id *)req->initiator_port_id;
22898c2ecf20Sopenharmony_ci	tport = (struct port_id *)req->target_port_id;
22908c2ecf20Sopenharmony_ci	fmt = (struct format_code *)&req->req_buf_fmt;
22918c2ecf20Sopenharmony_ci	if (be32_to_cpu(req->req_it_iu_len) > SRP_MAX_IU_LEN)
22928c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE;
22938c2ecf20Sopenharmony_ci	else if (be32_to_cpu(req->req_it_iu_len) < 64)
22948c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
22958c2ecf20Sopenharmony_ci	else if ((be64_to_cpu(iport->id_extension) > (MAX_NUM_PORTS - 1)) ||
22968c2ecf20Sopenharmony_ci		 (be64_to_cpu(tport->id_extension) > (MAX_NUM_PORTS - 1)))
22978c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL;
22988c2ecf20Sopenharmony_ci	else if (req->req_flags & SRP_MULTICHAN_MULTI)
22998c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED;
23008c2ecf20Sopenharmony_ci	else if (fmt->buffers & (~SUPPORTED_FORMATS))
23018c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
23028c2ecf20Sopenharmony_ci	else if ((fmt->buffers & SUPPORTED_FORMATS) == 0)
23038c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	if (vscsi->state == SRP_PROCESSING)
23068c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	rc = ibmvscsis_make_nexus(&vscsi->tport);
23098c2ecf20Sopenharmony_ci	if (rc)
23108c2ecf20Sopenharmony_ci		reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	cmd->rsp.format = VIOSRP_SRP_FORMAT;
23138c2ecf20Sopenharmony_ci	cmd->rsp.tag = req->tag;
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "srp_login: reason 0x%x\n", reason);
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	if (reason)
23188c2ecf20Sopenharmony_ci		rc = ibmvscsis_srp_login_rej(vscsi, cmd, reason);
23198c2ecf20Sopenharmony_ci	else
23208c2ecf20Sopenharmony_ci		rc = ibmvscsis_login_rsp(vscsi, cmd);
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	if (!rc) {
23238c2ecf20Sopenharmony_ci		if (!reason)
23248c2ecf20Sopenharmony_ci			vscsi->state = SRP_PROCESSING;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
23278c2ecf20Sopenharmony_ci		ibmvscsis_send_messages(vscsi);
23288c2ecf20Sopenharmony_ci	} else {
23298c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
23308c2ecf20Sopenharmony_ci	}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving srp_login, rc %ld\n", rc);
23338c2ecf20Sopenharmony_ci	return rc;
23348c2ecf20Sopenharmony_ci}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci/**
23378c2ecf20Sopenharmony_ci * ibmvscsis_srp_i_logout() - Helper Function to close I_T Nexus
23388c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
23398c2ecf20Sopenharmony_ci * @cmd:	Command element to use to process the Implicit Logout request
23408c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ entry containing the Implicit Logout request
23418c2ecf20Sopenharmony_ci *
23428c2ecf20Sopenharmony_ci * Do the logic to close the I_T nexus.  This function may not
23438c2ecf20Sopenharmony_ci * behave to specification.
23448c2ecf20Sopenharmony_ci *
23458c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
23468c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
23478c2ecf20Sopenharmony_ci */
23488c2ecf20Sopenharmony_cistatic long ibmvscsis_srp_i_logout(struct scsi_info *vscsi,
23498c2ecf20Sopenharmony_ci				   struct ibmvscsis_cmd *cmd,
23508c2ecf20Sopenharmony_ci				   struct viosrp_crq *crq)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
23538c2ecf20Sopenharmony_ci	struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if ((vscsi->debit > 0) || !list_empty(&vscsi->schedule_q) ||
23568c2ecf20Sopenharmony_ci	    !list_empty(&vscsi->waiting_rsp)) {
23578c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "i_logout: outstanding work\n");
23588c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
23598c2ecf20Sopenharmony_ci	} else {
23608c2ecf20Sopenharmony_ci		cmd->rsp.format = SRP_FORMAT;
23618c2ecf20Sopenharmony_ci		cmd->rsp.tag = log_out->tag;
23628c2ecf20Sopenharmony_ci		cmd->rsp.len = sizeof(struct mad_common);
23638c2ecf20Sopenharmony_ci		list_add_tail(&cmd->list, &vscsi->waiting_rsp);
23648c2ecf20Sopenharmony_ci		ibmvscsis_send_messages(vscsi);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
23678c2ecf20Sopenharmony_ci	}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	return ADAPT_SUCCESS;
23708c2ecf20Sopenharmony_ci}
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci/* Called with intr lock held */
23738c2ecf20Sopenharmony_cistatic void ibmvscsis_srp_cmd(struct scsi_info *vscsi, struct viosrp_crq *crq)
23748c2ecf20Sopenharmony_ci{
23758c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd;
23768c2ecf20Sopenharmony_ci	struct iu_entry *iue;
23778c2ecf20Sopenharmony_ci	struct srp_cmd *srp;
23788c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *tsk;
23798c2ecf20Sopenharmony_ci	long rc;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	if (vscsi->request_limit - vscsi->debit <= 0) {
23828c2ecf20Sopenharmony_ci		/* Client has exceeded request limit */
23838c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Client exceeded the request limit (%d), debit %d\n",
23848c2ecf20Sopenharmony_ci			vscsi->request_limit, vscsi->debit);
23858c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
23868c2ecf20Sopenharmony_ci		return;
23878c2ecf20Sopenharmony_ci	}
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	cmd = ibmvscsis_get_free_cmd(vscsi);
23908c2ecf20Sopenharmony_ci	if (!cmd) {
23918c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "srp_cmd failed to get cmd, debit %d\n",
23928c2ecf20Sopenharmony_ci			vscsi->debit);
23938c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
23948c2ecf20Sopenharmony_ci		return;
23958c2ecf20Sopenharmony_ci	}
23968c2ecf20Sopenharmony_ci	iue = cmd->iue;
23978c2ecf20Sopenharmony_ci	srp = &vio_iu(iue)->srp.cmd;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
24008c2ecf20Sopenharmony_ci	if (rc) {
24018c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
24028c2ecf20Sopenharmony_ci		return;
24038c2ecf20Sopenharmony_ci	}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	if (vscsi->state == SRP_PROCESSING) {
24068c2ecf20Sopenharmony_ci		switch (srp->opcode) {
24078c2ecf20Sopenharmony_ci		case SRP_LOGIN_REQ:
24088c2ecf20Sopenharmony_ci			rc = ibmvscsis_srp_login(vscsi, cmd, crq);
24098c2ecf20Sopenharmony_ci			break;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci		case SRP_TSK_MGMT:
24128c2ecf20Sopenharmony_ci			tsk = &vio_iu(iue)->srp.tsk_mgmt;
24138c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "tsk_mgmt tag: %llu (0x%llx)\n",
24148c2ecf20Sopenharmony_ci				tsk->tag, tsk->tag);
24158c2ecf20Sopenharmony_ci			cmd->rsp.tag = tsk->tag;
24168c2ecf20Sopenharmony_ci			vscsi->debit += 1;
24178c2ecf20Sopenharmony_ci			cmd->type = TASK_MANAGEMENT;
24188c2ecf20Sopenharmony_ci			list_add_tail(&cmd->list, &vscsi->schedule_q);
24198c2ecf20Sopenharmony_ci			queue_work(vscsi->work_q, &cmd->work);
24208c2ecf20Sopenharmony_ci			break;
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci		case SRP_CMD:
24238c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "srp_cmd tag: %llu (0x%llx)\n",
24248c2ecf20Sopenharmony_ci				srp->tag, srp->tag);
24258c2ecf20Sopenharmony_ci			cmd->rsp.tag = srp->tag;
24268c2ecf20Sopenharmony_ci			vscsi->debit += 1;
24278c2ecf20Sopenharmony_ci			cmd->type = SCSI_CDB;
24288c2ecf20Sopenharmony_ci			/*
24298c2ecf20Sopenharmony_ci			 * We want to keep track of work waiting for
24308c2ecf20Sopenharmony_ci			 * the workqueue.
24318c2ecf20Sopenharmony_ci			 */
24328c2ecf20Sopenharmony_ci			list_add_tail(&cmd->list, &vscsi->schedule_q);
24338c2ecf20Sopenharmony_ci			queue_work(vscsi->work_q, &cmd->work);
24348c2ecf20Sopenharmony_ci			break;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci		case SRP_I_LOGOUT:
24378c2ecf20Sopenharmony_ci			rc = ibmvscsis_srp_i_logout(vscsi, cmd, crq);
24388c2ecf20Sopenharmony_ci			break;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci		case SRP_CRED_RSP:
24418c2ecf20Sopenharmony_ci		case SRP_AER_RSP:
24428c2ecf20Sopenharmony_ci		default:
24438c2ecf20Sopenharmony_ci			ibmvscsis_free_cmd_resources(vscsi, cmd);
24448c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "invalid srp cmd, opcode %d\n",
24458c2ecf20Sopenharmony_ci				(uint)srp->opcode);
24468c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
24478c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
24488c2ecf20Sopenharmony_ci			break;
24498c2ecf20Sopenharmony_ci		}
24508c2ecf20Sopenharmony_ci	} else if (srp->opcode == SRP_LOGIN_REQ && vscsi->state == CONNECTED) {
24518c2ecf20Sopenharmony_ci		rc = ibmvscsis_srp_login(vscsi, cmd, crq);
24528c2ecf20Sopenharmony_ci	} else {
24538c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
24548c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Invalid state %d to handle srp cmd\n",
24558c2ecf20Sopenharmony_ci			vscsi->state);
24568c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
24578c2ecf20Sopenharmony_ci	}
24588c2ecf20Sopenharmony_ci}
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci/**
24618c2ecf20Sopenharmony_ci * ibmvscsis_ping_response() - Respond to a ping request
24628c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
24638c2ecf20Sopenharmony_ci *
24648c2ecf20Sopenharmony_ci * Let the client know that the server is alive and waiting on
24658c2ecf20Sopenharmony_ci * its native I/O stack.
24668c2ecf20Sopenharmony_ci * If any type of error occurs from the call to queue a ping
24678c2ecf20Sopenharmony_ci * response then the client is either not accepting or receiving
24688c2ecf20Sopenharmony_ci * interrupts.  Disconnect with an error.
24698c2ecf20Sopenharmony_ci *
24708c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
24718c2ecf20Sopenharmony_ci *	Interrupt, interrupt lock held
24728c2ecf20Sopenharmony_ci */
24738c2ecf20Sopenharmony_cistatic long ibmvscsis_ping_response(struct scsi_info *vscsi)
24748c2ecf20Sopenharmony_ci{
24758c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
24768c2ecf20Sopenharmony_ci	u64 buffer[2] = { 0, 0 };
24778c2ecf20Sopenharmony_ci	long rc;
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	crq = (struct viosrp_crq *)&buffer;
24808c2ecf20Sopenharmony_ci	crq->valid = VALID_CMD_RESP_EL;
24818c2ecf20Sopenharmony_ci	crq->format = (u8)MESSAGE_IN_CRQ;
24828c2ecf20Sopenharmony_ci	crq->status = PING_RESPONSE;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
24858c2ecf20Sopenharmony_ci			cpu_to_be64(buffer[MSG_LOW]));
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	switch (rc) {
24888c2ecf20Sopenharmony_ci	case H_SUCCESS:
24898c2ecf20Sopenharmony_ci		break;
24908c2ecf20Sopenharmony_ci	case H_CLOSED:
24918c2ecf20Sopenharmony_ci		vscsi->flags |= CLIENT_FAILED;
24928c2ecf20Sopenharmony_ci		fallthrough;
24938c2ecf20Sopenharmony_ci	case H_DROPPED:
24948c2ecf20Sopenharmony_ci		vscsi->flags |= RESPONSE_Q_DOWN;
24958c2ecf20Sopenharmony_ci		fallthrough;
24968c2ecf20Sopenharmony_ci	case H_REMOTE_PARM:
24978c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "ping_response: h_send_crq failed, rc %ld\n",
24988c2ecf20Sopenharmony_ci			rc);
24998c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
25008c2ecf20Sopenharmony_ci		break;
25018c2ecf20Sopenharmony_ci	default:
25028c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "ping_response: h_send_crq returned unknown rc %ld\n",
25038c2ecf20Sopenharmony_ci			rc);
25048c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
25058c2ecf20Sopenharmony_ci		break;
25068c2ecf20Sopenharmony_ci	}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	return rc;
25098c2ecf20Sopenharmony_ci}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci/**
25128c2ecf20Sopenharmony_ci * ibmvscsis_parse_command() - Parse an element taken from the cmd rsp queue.
25138c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
25148c2ecf20Sopenharmony_ci * @crq:	Pointer to CRQ element containing the SRP request
25158c2ecf20Sopenharmony_ci *
25168c2ecf20Sopenharmony_ci * This function will return success if the command queue element is valid
25178c2ecf20Sopenharmony_ci * and the srp iu or MAD request it pointed to was also valid.  That does
25188c2ecf20Sopenharmony_ci * not mean that an error was not returned to the client.
25198c2ecf20Sopenharmony_ci *
25208c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
25218c2ecf20Sopenharmony_ci *	Interrupt, intr lock held
25228c2ecf20Sopenharmony_ci */
25238c2ecf20Sopenharmony_cistatic long ibmvscsis_parse_command(struct scsi_info *vscsi,
25248c2ecf20Sopenharmony_ci				    struct viosrp_crq *crq)
25258c2ecf20Sopenharmony_ci{
25268c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	switch (crq->valid) {
25298c2ecf20Sopenharmony_ci	case VALID_CMD_RESP_EL:
25308c2ecf20Sopenharmony_ci		switch (crq->format) {
25318c2ecf20Sopenharmony_ci		case OS400_FORMAT:
25328c2ecf20Sopenharmony_ci		case AIX_FORMAT:
25338c2ecf20Sopenharmony_ci		case LINUX_FORMAT:
25348c2ecf20Sopenharmony_ci		case MAD_FORMAT:
25358c2ecf20Sopenharmony_ci			if (vscsi->flags & PROCESSING_MAD) {
25368c2ecf20Sopenharmony_ci				rc = ERROR;
25378c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "parse_command: already processing mad\n");
25388c2ecf20Sopenharmony_ci				ibmvscsis_post_disconnect(vscsi,
25398c2ecf20Sopenharmony_ci						       ERR_DISCONNECT_RECONNECT,
25408c2ecf20Sopenharmony_ci						       0);
25418c2ecf20Sopenharmony_ci			} else {
25428c2ecf20Sopenharmony_ci				vscsi->flags |= PROCESSING_MAD;
25438c2ecf20Sopenharmony_ci				rc = ibmvscsis_mad(vscsi, crq);
25448c2ecf20Sopenharmony_ci			}
25458c2ecf20Sopenharmony_ci			break;
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci		case SRP_FORMAT:
25488c2ecf20Sopenharmony_ci			ibmvscsis_srp_cmd(vscsi, crq);
25498c2ecf20Sopenharmony_ci			break;
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci		case MESSAGE_IN_CRQ:
25528c2ecf20Sopenharmony_ci			if (crq->status == PING)
25538c2ecf20Sopenharmony_ci				ibmvscsis_ping_response(vscsi);
25548c2ecf20Sopenharmony_ci			break;
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci		default:
25578c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "parse_command: invalid format %d\n",
25588c2ecf20Sopenharmony_ci				(uint)crq->format);
25598c2ecf20Sopenharmony_ci			ibmvscsis_post_disconnect(vscsi,
25608c2ecf20Sopenharmony_ci						  ERR_DISCONNECT_RECONNECT, 0);
25618c2ecf20Sopenharmony_ci			break;
25628c2ecf20Sopenharmony_ci		}
25638c2ecf20Sopenharmony_ci		break;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	case VALID_TRANS_EVENT:
25668c2ecf20Sopenharmony_ci		rc = ibmvscsis_trans_event(vscsi, crq);
25678c2ecf20Sopenharmony_ci		break;
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	case VALID_INIT_MSG:
25708c2ecf20Sopenharmony_ci		rc = ibmvscsis_init_msg(vscsi, crq);
25718c2ecf20Sopenharmony_ci		break;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	default:
25748c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "parse_command: invalid valid field %d\n",
25758c2ecf20Sopenharmony_ci			(uint)crq->valid);
25768c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
25778c2ecf20Sopenharmony_ci		break;
25788c2ecf20Sopenharmony_ci	}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	/*
25818c2ecf20Sopenharmony_ci	 * Return only what the interrupt handler cares
25828c2ecf20Sopenharmony_ci	 * about. Most errors we keep right on trucking.
25838c2ecf20Sopenharmony_ci	 */
25848c2ecf20Sopenharmony_ci	rc = vscsi->flags & SCHEDULE_DISCONNECT;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	return rc;
25878c2ecf20Sopenharmony_ci}
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_cistatic int read_dma_window(struct scsi_info *vscsi)
25908c2ecf20Sopenharmony_ci{
25918c2ecf20Sopenharmony_ci	struct vio_dev *vdev = vscsi->dma_dev;
25928c2ecf20Sopenharmony_ci	const __be32 *dma_window;
25938c2ecf20Sopenharmony_ci	const __be32 *prop;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	/* TODO Using of_parse_dma_window would be better, but it doesn't give
25968c2ecf20Sopenharmony_ci	 * a way to read multiple windows without already knowing the size of
25978c2ecf20Sopenharmony_ci	 * a window or the number of windows.
25988c2ecf20Sopenharmony_ci	 */
25998c2ecf20Sopenharmony_ci	dma_window = (const __be32 *)vio_get_attribute(vdev,
26008c2ecf20Sopenharmony_ci						       "ibm,my-dma-window",
26018c2ecf20Sopenharmony_ci						       NULL);
26028c2ecf20Sopenharmony_ci	if (!dma_window) {
26038c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Couldn't find ibm,my-dma-window property\n");
26048c2ecf20Sopenharmony_ci		return -1;
26058c2ecf20Sopenharmony_ci	}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	vscsi->dds.window[LOCAL].liobn = be32_to_cpu(*dma_window);
26088c2ecf20Sopenharmony_ci	dma_window++;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
26118c2ecf20Sopenharmony_ci						 NULL);
26128c2ecf20Sopenharmony_ci	if (!prop) {
26138c2ecf20Sopenharmony_ci		dev_warn(&vscsi->dev, "Couldn't find ibm,#dma-address-cells property\n");
26148c2ecf20Sopenharmony_ci		dma_window++;
26158c2ecf20Sopenharmony_ci	} else {
26168c2ecf20Sopenharmony_ci		dma_window += be32_to_cpu(*prop);
26178c2ecf20Sopenharmony_ci	}
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
26208c2ecf20Sopenharmony_ci						 NULL);
26218c2ecf20Sopenharmony_ci	if (!prop) {
26228c2ecf20Sopenharmony_ci		dev_warn(&vscsi->dev, "Couldn't find ibm,#dma-size-cells property\n");
26238c2ecf20Sopenharmony_ci		dma_window++;
26248c2ecf20Sopenharmony_ci	} else {
26258c2ecf20Sopenharmony_ci		dma_window += be32_to_cpu(*prop);
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	/* dma_window should point to the second window now */
26298c2ecf20Sopenharmony_ci	vscsi->dds.window[REMOTE].liobn = be32_to_cpu(*dma_window);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	return 0;
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_cistatic struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
26358c2ecf20Sopenharmony_ci{
26368c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport = NULL;
26378c2ecf20Sopenharmony_ci	struct vio_dev *vdev;
26388c2ecf20Sopenharmony_ci	struct scsi_info *vscsi;
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	spin_lock_bh(&ibmvscsis_dev_lock);
26418c2ecf20Sopenharmony_ci	list_for_each_entry(vscsi, &ibmvscsis_dev_list, list) {
26428c2ecf20Sopenharmony_ci		vdev = vscsi->dma_dev;
26438c2ecf20Sopenharmony_ci		if (!strcmp(dev_name(&vdev->dev), name)) {
26448c2ecf20Sopenharmony_ci			tport = &vscsi->tport;
26458c2ecf20Sopenharmony_ci			break;
26468c2ecf20Sopenharmony_ci		}
26478c2ecf20Sopenharmony_ci	}
26488c2ecf20Sopenharmony_ci	spin_unlock_bh(&ibmvscsis_dev_lock);
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	return tport;
26518c2ecf20Sopenharmony_ci}
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci/**
26548c2ecf20Sopenharmony_ci * ibmvscsis_parse_cmd() - Parse SRP Command
26558c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
26568c2ecf20Sopenharmony_ci * @cmd:	Pointer to command element with SRP command
26578c2ecf20Sopenharmony_ci *
26588c2ecf20Sopenharmony_ci * Parse the srp command; if it is valid then submit it to tcm.
26598c2ecf20Sopenharmony_ci * Note: The return code does not reflect the status of the SCSI CDB.
26608c2ecf20Sopenharmony_ci *
26618c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
26628c2ecf20Sopenharmony_ci *	Process level
26638c2ecf20Sopenharmony_ci */
26648c2ecf20Sopenharmony_cistatic void ibmvscsis_parse_cmd(struct scsi_info *vscsi,
26658c2ecf20Sopenharmony_ci				struct ibmvscsis_cmd *cmd)
26668c2ecf20Sopenharmony_ci{
26678c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
26688c2ecf20Sopenharmony_ci	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
26698c2ecf20Sopenharmony_ci	struct ibmvscsis_nexus *nexus;
26708c2ecf20Sopenharmony_ci	u64 data_len = 0;
26718c2ecf20Sopenharmony_ci	enum dma_data_direction dir;
26728c2ecf20Sopenharmony_ci	int attr = 0;
26738c2ecf20Sopenharmony_ci	int rc = 0;
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci	nexus = vscsi->tport.ibmv_nexus;
26768c2ecf20Sopenharmony_ci	/*
26778c2ecf20Sopenharmony_ci	 * additional length in bytes.  Note that the SRP spec says that
26788c2ecf20Sopenharmony_ci	 * additional length is in 4-byte words, but technically the
26798c2ecf20Sopenharmony_ci	 * additional length field is only the upper 6 bits of the byte.
26808c2ecf20Sopenharmony_ci	 * The lower 2 bits are reserved.  If the lower 2 bits are 0 (as
26818c2ecf20Sopenharmony_ci	 * all reserved fields should be), then interpreting the byte as
26828c2ecf20Sopenharmony_ci	 * an int will yield the length in bytes.
26838c2ecf20Sopenharmony_ci	 */
26848c2ecf20Sopenharmony_ci	if (srp->add_cdb_len & 0x03) {
26858c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "parse_cmd: reserved bits set in IU\n");
26868c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
26878c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
26888c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
26898c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
26908c2ecf20Sopenharmony_ci		return;
26918c2ecf20Sopenharmony_ci	}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci	if (srp_get_desc_table(srp, &dir, &data_len)) {
26948c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "0x%llx: parsing SRP descriptor table failed.\n",
26958c2ecf20Sopenharmony_ci			srp->tag);
26968c2ecf20Sopenharmony_ci		goto fail;
26978c2ecf20Sopenharmony_ci	}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	cmd->rsp.sol_not = srp->sol_not;
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	switch (srp->task_attr) {
27028c2ecf20Sopenharmony_ci	case SRP_SIMPLE_TASK:
27038c2ecf20Sopenharmony_ci		attr = TCM_SIMPLE_TAG;
27048c2ecf20Sopenharmony_ci		break;
27058c2ecf20Sopenharmony_ci	case SRP_ORDERED_TASK:
27068c2ecf20Sopenharmony_ci		attr = TCM_ORDERED_TAG;
27078c2ecf20Sopenharmony_ci		break;
27088c2ecf20Sopenharmony_ci	case SRP_HEAD_TASK:
27098c2ecf20Sopenharmony_ci		attr = TCM_HEAD_TAG;
27108c2ecf20Sopenharmony_ci		break;
27118c2ecf20Sopenharmony_ci	case SRP_ACA_TASK:
27128c2ecf20Sopenharmony_ci		attr = TCM_ACA_TAG;
27138c2ecf20Sopenharmony_ci		break;
27148c2ecf20Sopenharmony_ci	default:
27158c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Invalid task attribute %d\n",
27168c2ecf20Sopenharmony_ci			srp->task_attr);
27178c2ecf20Sopenharmony_ci		goto fail;
27188c2ecf20Sopenharmony_ci	}
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci	cmd->se_cmd.tag = be64_to_cpu(srp->tag);
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
27238c2ecf20Sopenharmony_ci	list_add_tail(&cmd->list, &vscsi->active_q);
27248c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	srp->lun.scsi_lun[0] &= 0x3f;
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci	rc = target_submit_cmd(&cmd->se_cmd, nexus->se_sess, srp->cdb,
27298c2ecf20Sopenharmony_ci			       cmd->sense_buf, scsilun_to_int(&srp->lun),
27308c2ecf20Sopenharmony_ci			       data_len, attr, dir, 0);
27318c2ecf20Sopenharmony_ci	if (rc) {
27328c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "target_submit_cmd failed, rc %d\n", rc);
27338c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
27348c2ecf20Sopenharmony_ci		list_del(&cmd->list);
27358c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
27368c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
27378c2ecf20Sopenharmony_ci		goto fail;
27388c2ecf20Sopenharmony_ci	}
27398c2ecf20Sopenharmony_ci	return;
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_cifail:
27428c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
27438c2ecf20Sopenharmony_ci	ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
27448c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
27458c2ecf20Sopenharmony_ci}
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci/**
27488c2ecf20Sopenharmony_ci * ibmvscsis_parse_task() - Parse SRP Task Management Request
27498c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
27508c2ecf20Sopenharmony_ci * @cmd:	Pointer to command element with SRP task management request
27518c2ecf20Sopenharmony_ci *
27528c2ecf20Sopenharmony_ci * Parse the srp task management request; if it is valid then submit it to tcm.
27538c2ecf20Sopenharmony_ci * Note: The return code does not reflect the status of the task management
27548c2ecf20Sopenharmony_ci * request.
27558c2ecf20Sopenharmony_ci *
27568c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
27578c2ecf20Sopenharmony_ci *	Processor level
27588c2ecf20Sopenharmony_ci */
27598c2ecf20Sopenharmony_cistatic void ibmvscsis_parse_task(struct scsi_info *vscsi,
27608c2ecf20Sopenharmony_ci				 struct ibmvscsis_cmd *cmd)
27618c2ecf20Sopenharmony_ci{
27628c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
27638c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
27648c2ecf20Sopenharmony_ci	int tcm_type;
27658c2ecf20Sopenharmony_ci	u64 tag_to_abort = 0;
27668c2ecf20Sopenharmony_ci	int rc = 0;
27678c2ecf20Sopenharmony_ci	struct ibmvscsis_nexus *nexus;
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	nexus = vscsi->tport.ibmv_nexus;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	cmd->rsp.sol_not = srp_tsk->sol_not;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	switch (srp_tsk->tsk_mgmt_func) {
27748c2ecf20Sopenharmony_ci	case SRP_TSK_ABORT_TASK:
27758c2ecf20Sopenharmony_ci		tcm_type = TMR_ABORT_TASK;
27768c2ecf20Sopenharmony_ci		tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
27778c2ecf20Sopenharmony_ci		break;
27788c2ecf20Sopenharmony_ci	case SRP_TSK_ABORT_TASK_SET:
27798c2ecf20Sopenharmony_ci		tcm_type = TMR_ABORT_TASK_SET;
27808c2ecf20Sopenharmony_ci		break;
27818c2ecf20Sopenharmony_ci	case SRP_TSK_CLEAR_TASK_SET:
27828c2ecf20Sopenharmony_ci		tcm_type = TMR_CLEAR_TASK_SET;
27838c2ecf20Sopenharmony_ci		break;
27848c2ecf20Sopenharmony_ci	case SRP_TSK_LUN_RESET:
27858c2ecf20Sopenharmony_ci		tcm_type = TMR_LUN_RESET;
27868c2ecf20Sopenharmony_ci		break;
27878c2ecf20Sopenharmony_ci	case SRP_TSK_CLEAR_ACA:
27888c2ecf20Sopenharmony_ci		tcm_type = TMR_CLEAR_ACA;
27898c2ecf20Sopenharmony_ci		break;
27908c2ecf20Sopenharmony_ci	default:
27918c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "unknown task mgmt func %d\n",
27928c2ecf20Sopenharmony_ci			srp_tsk->tsk_mgmt_func);
27938c2ecf20Sopenharmony_ci		cmd->se_cmd.se_tmr_req->response =
27948c2ecf20Sopenharmony_ci			TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
27958c2ecf20Sopenharmony_ci		rc = -1;
27968c2ecf20Sopenharmony_ci		break;
27978c2ecf20Sopenharmony_ci	}
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	if (!rc) {
28008c2ecf20Sopenharmony_ci		cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
28038c2ecf20Sopenharmony_ci		list_add_tail(&cmd->list, &vscsi->active_q);
28048c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci		srp_tsk->lun.scsi_lun[0] &= 0x3f;
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "calling submit_tmr, func %d\n",
28098c2ecf20Sopenharmony_ci			srp_tsk->tsk_mgmt_func);
28108c2ecf20Sopenharmony_ci		rc = target_submit_tmr(&cmd->se_cmd, nexus->se_sess, NULL,
28118c2ecf20Sopenharmony_ci				       scsilun_to_int(&srp_tsk->lun), srp_tsk,
28128c2ecf20Sopenharmony_ci				       tcm_type, GFP_KERNEL, tag_to_abort, 0);
28138c2ecf20Sopenharmony_ci		if (rc) {
28148c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "target_submit_tmr failed, rc %d\n",
28158c2ecf20Sopenharmony_ci				rc);
28168c2ecf20Sopenharmony_ci			spin_lock_bh(&vscsi->intr_lock);
28178c2ecf20Sopenharmony_ci			list_del(&cmd->list);
28188c2ecf20Sopenharmony_ci			spin_unlock_bh(&vscsi->intr_lock);
28198c2ecf20Sopenharmony_ci			cmd->se_cmd.se_tmr_req->response =
28208c2ecf20Sopenharmony_ci				TMR_FUNCTION_REJECTED;
28218c2ecf20Sopenharmony_ci		}
28228c2ecf20Sopenharmony_ci	}
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	if (rc)
28258c2ecf20Sopenharmony_ci		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
28268c2ecf20Sopenharmony_ci}
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_cistatic void ibmvscsis_scheduler(struct work_struct *work)
28298c2ecf20Sopenharmony_ci{
28308c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(work, struct ibmvscsis_cmd,
28318c2ecf20Sopenharmony_ci						 work);
28328c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
28338c2ecf20Sopenharmony_ci
28348c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	/* Remove from schedule_q */
28378c2ecf20Sopenharmony_ci	list_del(&cmd->list);
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	/* Don't submit cmd if we're disconnecting */
28408c2ecf20Sopenharmony_ci	if (vscsi->flags & (SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED)) {
28418c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci		/* ibmvscsis_disconnect might be waiting for us */
28448c2ecf20Sopenharmony_ci		if (list_empty(&vscsi->active_q) &&
28458c2ecf20Sopenharmony_ci		    list_empty(&vscsi->schedule_q) &&
28468c2ecf20Sopenharmony_ci		    (vscsi->flags & WAIT_FOR_IDLE)) {
28478c2ecf20Sopenharmony_ci			vscsi->flags &= ~WAIT_FOR_IDLE;
28488c2ecf20Sopenharmony_ci			complete(&vscsi->wait_idle);
28498c2ecf20Sopenharmony_ci		}
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
28528c2ecf20Sopenharmony_ci		return;
28538c2ecf20Sopenharmony_ci	}
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	switch (cmd->type) {
28588c2ecf20Sopenharmony_ci	case SCSI_CDB:
28598c2ecf20Sopenharmony_ci		ibmvscsis_parse_cmd(vscsi, cmd);
28608c2ecf20Sopenharmony_ci		break;
28618c2ecf20Sopenharmony_ci	case TASK_MANAGEMENT:
28628c2ecf20Sopenharmony_ci		ibmvscsis_parse_task(vscsi, cmd);
28638c2ecf20Sopenharmony_ci		break;
28648c2ecf20Sopenharmony_ci	default:
28658c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "scheduler, invalid cmd type %d\n",
28668c2ecf20Sopenharmony_ci			cmd->type);
28678c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
28688c2ecf20Sopenharmony_ci		ibmvscsis_free_cmd_resources(vscsi, cmd);
28698c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
28708c2ecf20Sopenharmony_ci		break;
28718c2ecf20Sopenharmony_ci	}
28728c2ecf20Sopenharmony_ci}
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_cistatic int ibmvscsis_alloc_cmds(struct scsi_info *vscsi, int num)
28758c2ecf20Sopenharmony_ci{
28768c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd;
28778c2ecf20Sopenharmony_ci	int i;
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vscsi->free_cmd);
28808c2ecf20Sopenharmony_ci	vscsi->cmd_pool = kcalloc(num, sizeof(struct ibmvscsis_cmd),
28818c2ecf20Sopenharmony_ci				  GFP_KERNEL);
28828c2ecf20Sopenharmony_ci	if (!vscsi->cmd_pool)
28838c2ecf20Sopenharmony_ci		return -ENOMEM;
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	for (i = 0, cmd = (struct ibmvscsis_cmd *)vscsi->cmd_pool; i < num;
28868c2ecf20Sopenharmony_ci	     i++, cmd++) {
28878c2ecf20Sopenharmony_ci		cmd->abort_cmd = NULL;
28888c2ecf20Sopenharmony_ci		cmd->adapter = vscsi;
28898c2ecf20Sopenharmony_ci		INIT_WORK(&cmd->work, ibmvscsis_scheduler);
28908c2ecf20Sopenharmony_ci		list_add_tail(&cmd->list, &vscsi->free_cmd);
28918c2ecf20Sopenharmony_ci	}
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci	return 0;
28948c2ecf20Sopenharmony_ci}
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_cistatic void ibmvscsis_free_cmds(struct scsi_info *vscsi)
28978c2ecf20Sopenharmony_ci{
28988c2ecf20Sopenharmony_ci	kfree(vscsi->cmd_pool);
28998c2ecf20Sopenharmony_ci	vscsi->cmd_pool = NULL;
29008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vscsi->free_cmd);
29018c2ecf20Sopenharmony_ci}
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci/**
29048c2ecf20Sopenharmony_ci * ibmvscsis_service_wait_q() - Service Waiting Queue
29058c2ecf20Sopenharmony_ci * @timer:	Pointer to timer which has expired
29068c2ecf20Sopenharmony_ci *
29078c2ecf20Sopenharmony_ci * This routine is called when the timer pops to service the waiting
29088c2ecf20Sopenharmony_ci * queue. Elements on the queue have completed, their responses have been
29098c2ecf20Sopenharmony_ci * copied to the client, but the client's response queue was full so
29108c2ecf20Sopenharmony_ci * the queue message could not be sent. The routine grabs the proper locks
29118c2ecf20Sopenharmony_ci * and calls send messages.
29128c2ecf20Sopenharmony_ci *
29138c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
29148c2ecf20Sopenharmony_ci *	called at interrupt level
29158c2ecf20Sopenharmony_ci */
29168c2ecf20Sopenharmony_cistatic enum hrtimer_restart ibmvscsis_service_wait_q(struct hrtimer *timer)
29178c2ecf20Sopenharmony_ci{
29188c2ecf20Sopenharmony_ci	struct timer_cb *p_timer = container_of(timer, struct timer_cb, timer);
29198c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(p_timer, struct scsi_info,
29208c2ecf20Sopenharmony_ci					       rsp_q_timer);
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
29238c2ecf20Sopenharmony_ci	p_timer->timer_pops += 1;
29248c2ecf20Sopenharmony_ci	p_timer->started = false;
29258c2ecf20Sopenharmony_ci	ibmvscsis_send_messages(vscsi);
29268c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
29298c2ecf20Sopenharmony_ci}
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_cistatic long ibmvscsis_alloctimer(struct scsi_info *vscsi)
29328c2ecf20Sopenharmony_ci{
29338c2ecf20Sopenharmony_ci	struct timer_cb *p_timer;
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	p_timer = &vscsi->rsp_q_timer;
29368c2ecf20Sopenharmony_ci	hrtimer_init(&p_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	p_timer->timer.function = ibmvscsis_service_wait_q;
29398c2ecf20Sopenharmony_ci	p_timer->started = false;
29408c2ecf20Sopenharmony_ci	p_timer->timer_pops = 0;
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci	return ADAPT_SUCCESS;
29438c2ecf20Sopenharmony_ci}
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_cistatic void ibmvscsis_freetimer(struct scsi_info *vscsi)
29468c2ecf20Sopenharmony_ci{
29478c2ecf20Sopenharmony_ci	struct timer_cb *p_timer;
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	p_timer = &vscsi->rsp_q_timer;
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	(void)hrtimer_cancel(&p_timer->timer);
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	p_timer->started = false;
29548c2ecf20Sopenharmony_ci	p_timer->timer_pops = 0;
29558c2ecf20Sopenharmony_ci}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_cistatic irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
29588c2ecf20Sopenharmony_ci{
29598c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = data;
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	vio_disable_interrupts(vscsi->dma_dev);
29628c2ecf20Sopenharmony_ci	tasklet_schedule(&vscsi->work_task);
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
29658c2ecf20Sopenharmony_ci}
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci/**
29688c2ecf20Sopenharmony_ci * ibmvscsis_enable_change_state() - Set new state based on enabled status
29698c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
29708c2ecf20Sopenharmony_ci *
29718c2ecf20Sopenharmony_ci * This function determines our new state now that we are enabled.  This
29728c2ecf20Sopenharmony_ci * may involve sending an Init Complete message to the client.
29738c2ecf20Sopenharmony_ci *
29748c2ecf20Sopenharmony_ci * Must be called with interrupt lock held.
29758c2ecf20Sopenharmony_ci */
29768c2ecf20Sopenharmony_cistatic long ibmvscsis_enable_change_state(struct scsi_info *vscsi)
29778c2ecf20Sopenharmony_ci{
29788c2ecf20Sopenharmony_ci	int bytes;
29798c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_ci	bytes = vscsi->cmd_q.size * PAGE_SIZE;
29828c2ecf20Sopenharmony_ci	rc = h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, bytes);
29838c2ecf20Sopenharmony_ci	if (rc == H_CLOSED || rc == H_SUCCESS) {
29848c2ecf20Sopenharmony_ci		vscsi->state = WAIT_CONNECTION;
29858c2ecf20Sopenharmony_ci		rc = ibmvscsis_establish_new_q(vscsi);
29868c2ecf20Sopenharmony_ci	}
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	if (rc != ADAPT_SUCCESS) {
29898c2ecf20Sopenharmony_ci		vscsi->state = ERR_DISCONNECTED;
29908c2ecf20Sopenharmony_ci		vscsi->flags |= RESPONSE_Q_DOWN;
29918c2ecf20Sopenharmony_ci	}
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	return rc;
29948c2ecf20Sopenharmony_ci}
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci/**
29978c2ecf20Sopenharmony_ci * ibmvscsis_create_command_q() - Create Command Queue
29988c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
29998c2ecf20Sopenharmony_ci * @num_cmds:	Currently unused.  In the future, may be used to determine
30008c2ecf20Sopenharmony_ci *		the size of the CRQ.
30018c2ecf20Sopenharmony_ci *
30028c2ecf20Sopenharmony_ci * Allocates memory for command queue maps remote memory into an ioba
30038c2ecf20Sopenharmony_ci * initializes the command response queue
30048c2ecf20Sopenharmony_ci *
30058c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
30068c2ecf20Sopenharmony_ci *	Process level only
30078c2ecf20Sopenharmony_ci */
30088c2ecf20Sopenharmony_cistatic long ibmvscsis_create_command_q(struct scsi_info *vscsi, int num_cmds)
30098c2ecf20Sopenharmony_ci{
30108c2ecf20Sopenharmony_ci	int pages;
30118c2ecf20Sopenharmony_ci	struct vio_dev *vdev = vscsi->dma_dev;
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	/* We might support multiple pages in the future, but just 1 for now */
30148c2ecf20Sopenharmony_ci	pages = 1;
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ci	vscsi->cmd_q.size = pages;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	vscsi->cmd_q.base_addr =
30198c2ecf20Sopenharmony_ci		(struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
30208c2ecf20Sopenharmony_ci	if (!vscsi->cmd_q.base_addr)
30218c2ecf20Sopenharmony_ci		return -ENOMEM;
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	vscsi->cmd_q.mask = ((uint)pages * CRQ_PER_PAGE) - 1;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	vscsi->cmd_q.crq_token = dma_map_single(&vdev->dev,
30268c2ecf20Sopenharmony_ci						vscsi->cmd_q.base_addr,
30278c2ecf20Sopenharmony_ci						PAGE_SIZE, DMA_BIDIRECTIONAL);
30288c2ecf20Sopenharmony_ci	if (dma_mapping_error(&vdev->dev, vscsi->cmd_q.crq_token)) {
30298c2ecf20Sopenharmony_ci		free_page((unsigned long)vscsi->cmd_q.base_addr);
30308c2ecf20Sopenharmony_ci		return -ENOMEM;
30318c2ecf20Sopenharmony_ci	}
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	return 0;
30348c2ecf20Sopenharmony_ci}
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci/**
30378c2ecf20Sopenharmony_ci * ibmvscsis_destroy_command_q - Destroy Command Queue
30388c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
30398c2ecf20Sopenharmony_ci *
30408c2ecf20Sopenharmony_ci * Releases memory for command queue and unmaps mapped remote memory.
30418c2ecf20Sopenharmony_ci *
30428c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT:
30438c2ecf20Sopenharmony_ci *	Process level only
30448c2ecf20Sopenharmony_ci */
30458c2ecf20Sopenharmony_cistatic void ibmvscsis_destroy_command_q(struct scsi_info *vscsi)
30468c2ecf20Sopenharmony_ci{
30478c2ecf20Sopenharmony_ci	dma_unmap_single(&vscsi->dma_dev->dev, vscsi->cmd_q.crq_token,
30488c2ecf20Sopenharmony_ci			 PAGE_SIZE, DMA_BIDIRECTIONAL);
30498c2ecf20Sopenharmony_ci	free_page((unsigned long)vscsi->cmd_q.base_addr);
30508c2ecf20Sopenharmony_ci	vscsi->cmd_q.base_addr = NULL;
30518c2ecf20Sopenharmony_ci	vscsi->state = NO_QUEUE;
30528c2ecf20Sopenharmony_ci}
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_cistatic u8 ibmvscsis_fast_fail(struct scsi_info *vscsi,
30558c2ecf20Sopenharmony_ci			      struct ibmvscsis_cmd *cmd)
30568c2ecf20Sopenharmony_ci{
30578c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
30588c2ecf20Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
30598c2ecf20Sopenharmony_ci	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
30608c2ecf20Sopenharmony_ci	struct scsi_sense_hdr sshdr;
30618c2ecf20Sopenharmony_ci	u8 rc = se_cmd->scsi_status;
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	if (vscsi->fast_fail && (READ_CMD(srp->cdb) || WRITE_CMD(srp->cdb)))
30648c2ecf20Sopenharmony_ci		if (scsi_normalize_sense(se_cmd->sense_buffer,
30658c2ecf20Sopenharmony_ci					 se_cmd->scsi_sense_length, &sshdr))
30668c2ecf20Sopenharmony_ci			if (sshdr.sense_key == HARDWARE_ERROR &&
30678c2ecf20Sopenharmony_ci			    (se_cmd->residual_count == 0 ||
30688c2ecf20Sopenharmony_ci			     se_cmd->residual_count == se_cmd->data_length)) {
30698c2ecf20Sopenharmony_ci				rc = NO_SENSE;
30708c2ecf20Sopenharmony_ci				cmd->flags |= CMD_FAST_FAIL;
30718c2ecf20Sopenharmony_ci			}
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	return rc;
30748c2ecf20Sopenharmony_ci}
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci/**
30778c2ecf20Sopenharmony_ci * srp_build_response() - Build an SRP response buffer
30788c2ecf20Sopenharmony_ci * @vscsi:	Pointer to our adapter structure
30798c2ecf20Sopenharmony_ci * @cmd:	Pointer to command for which to send the response
30808c2ecf20Sopenharmony_ci * @len_p:	Where to return the length of the IU response sent.  This
30818c2ecf20Sopenharmony_ci *		is needed to construct the CRQ response.
30828c2ecf20Sopenharmony_ci *
30838c2ecf20Sopenharmony_ci * Build the SRP response buffer and copy it to the client's memory space.
30848c2ecf20Sopenharmony_ci */
30858c2ecf20Sopenharmony_cistatic long srp_build_response(struct scsi_info *vscsi,
30868c2ecf20Sopenharmony_ci			       struct ibmvscsis_cmd *cmd, uint *len_p)
30878c2ecf20Sopenharmony_ci{
30888c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
30898c2ecf20Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
30908c2ecf20Sopenharmony_ci	struct srp_rsp *rsp;
30918c2ecf20Sopenharmony_ci	uint len;
30928c2ecf20Sopenharmony_ci	u32 rsp_code;
30938c2ecf20Sopenharmony_ci	char *data;
30948c2ecf20Sopenharmony_ci	u32 *tsk_status;
30958c2ecf20Sopenharmony_ci	long rc = ADAPT_SUCCESS;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	rsp = &vio_iu(iue)->srp.rsp;
31008c2ecf20Sopenharmony_ci	len = sizeof(*rsp);
31018c2ecf20Sopenharmony_ci	memset(rsp, 0, len);
31028c2ecf20Sopenharmony_ci	data = rsp->data;
31038c2ecf20Sopenharmony_ci
31048c2ecf20Sopenharmony_ci	rsp->opcode = SRP_RSP;
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	rsp->req_lim_delta = cpu_to_be32(1 + vscsi->credit);
31078c2ecf20Sopenharmony_ci	rsp->tag = cmd->rsp.tag;
31088c2ecf20Sopenharmony_ci	rsp->flags = 0;
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_ci	if (cmd->type == SCSI_CDB) {
31118c2ecf20Sopenharmony_ci		rsp->status = ibmvscsis_fast_fail(vscsi, cmd);
31128c2ecf20Sopenharmony_ci		if (rsp->status) {
31138c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "build_resp: cmd %p, scsi status %d\n",
31148c2ecf20Sopenharmony_ci				cmd, (int)rsp->status);
31158c2ecf20Sopenharmony_ci			ibmvscsis_determine_resid(se_cmd, rsp);
31168c2ecf20Sopenharmony_ci			if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
31178c2ecf20Sopenharmony_ci				rsp->sense_data_len =
31188c2ecf20Sopenharmony_ci					cpu_to_be32(se_cmd->scsi_sense_length);
31198c2ecf20Sopenharmony_ci				rsp->flags |= SRP_RSP_FLAG_SNSVALID;
31208c2ecf20Sopenharmony_ci				len += se_cmd->scsi_sense_length;
31218c2ecf20Sopenharmony_ci				memcpy(data, se_cmd->sense_buffer,
31228c2ecf20Sopenharmony_ci				       se_cmd->scsi_sense_length);
31238c2ecf20Sopenharmony_ci			}
31248c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
31258c2ecf20Sopenharmony_ci				UCSOLNT_RESP_SHIFT;
31268c2ecf20Sopenharmony_ci		} else if (cmd->flags & CMD_FAST_FAIL) {
31278c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "build_resp: cmd %p, fast fail\n",
31288c2ecf20Sopenharmony_ci				cmd);
31298c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
31308c2ecf20Sopenharmony_ci				UCSOLNT_RESP_SHIFT;
31318c2ecf20Sopenharmony_ci		} else {
31328c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
31338c2ecf20Sopenharmony_ci				SCSOLNT_RESP_SHIFT;
31348c2ecf20Sopenharmony_ci		}
31358c2ecf20Sopenharmony_ci	} else {
31368c2ecf20Sopenharmony_ci		/* this is task management */
31378c2ecf20Sopenharmony_ci		rsp->status = 0;
31388c2ecf20Sopenharmony_ci		rsp->resp_data_len = cpu_to_be32(4);
31398c2ecf20Sopenharmony_ci		rsp->flags |= SRP_RSP_FLAG_RSPVALID;
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci		switch (se_cmd->se_tmr_req->response) {
31428c2ecf20Sopenharmony_ci		case TMR_FUNCTION_COMPLETE:
31438c2ecf20Sopenharmony_ci		case TMR_TASK_DOES_NOT_EXIST:
31448c2ecf20Sopenharmony_ci			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
31458c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
31468c2ecf20Sopenharmony_ci				SCSOLNT_RESP_SHIFT;
31478c2ecf20Sopenharmony_ci			break;
31488c2ecf20Sopenharmony_ci		case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
31498c2ecf20Sopenharmony_ci		case TMR_LUN_DOES_NOT_EXIST:
31508c2ecf20Sopenharmony_ci			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
31518c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
31528c2ecf20Sopenharmony_ci				UCSOLNT_RESP_SHIFT;
31538c2ecf20Sopenharmony_ci			break;
31548c2ecf20Sopenharmony_ci		case TMR_FUNCTION_FAILED:
31558c2ecf20Sopenharmony_ci		case TMR_FUNCTION_REJECTED:
31568c2ecf20Sopenharmony_ci		default:
31578c2ecf20Sopenharmony_ci			rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
31588c2ecf20Sopenharmony_ci			rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
31598c2ecf20Sopenharmony_ci				UCSOLNT_RESP_SHIFT;
31608c2ecf20Sopenharmony_ci			break;
31618c2ecf20Sopenharmony_ci		}
31628c2ecf20Sopenharmony_ci
31638c2ecf20Sopenharmony_ci		tsk_status = (u32 *)data;
31648c2ecf20Sopenharmony_ci		*tsk_status = cpu_to_be32(rsp_code);
31658c2ecf20Sopenharmony_ci		data = (char *)(tsk_status + 1);
31668c2ecf20Sopenharmony_ci		len += 4;
31678c2ecf20Sopenharmony_ci	}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	dma_wmb();
31708c2ecf20Sopenharmony_ci	rc = h_copy_rdma(len, vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
31718c2ecf20Sopenharmony_ci			 vscsi->dds.window[REMOTE].liobn,
31728c2ecf20Sopenharmony_ci			 be64_to_cpu(iue->remote_token));
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	switch (rc) {
31758c2ecf20Sopenharmony_ci	case H_SUCCESS:
31768c2ecf20Sopenharmony_ci		vscsi->credit = 0;
31778c2ecf20Sopenharmony_ci		*len_p = len;
31788c2ecf20Sopenharmony_ci		break;
31798c2ecf20Sopenharmony_ci	case H_PERMISSION:
31808c2ecf20Sopenharmony_ci		if (connection_broken(vscsi))
31818c2ecf20Sopenharmony_ci			vscsi->flags |= RESPONSE_Q_DOWN | CLIENT_FAILED;
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld, flags 0x%x, state 0x%hx\n",
31848c2ecf20Sopenharmony_ci			rc, vscsi->flags, vscsi->state);
31858c2ecf20Sopenharmony_ci		break;
31868c2ecf20Sopenharmony_ci	case H_SOURCE_PARM:
31878c2ecf20Sopenharmony_ci	case H_DEST_PARM:
31888c2ecf20Sopenharmony_ci	default:
31898c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld\n",
31908c2ecf20Sopenharmony_ci			rc);
31918c2ecf20Sopenharmony_ci		break;
31928c2ecf20Sopenharmony_ci	}
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	return rc;
31978c2ecf20Sopenharmony_ci}
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_cistatic int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, struct scatterlist *sg,
32008c2ecf20Sopenharmony_ci			  int nsg, struct srp_direct_buf *md, int nmd,
32018c2ecf20Sopenharmony_ci			  enum dma_data_direction dir, unsigned int bytes)
32028c2ecf20Sopenharmony_ci{
32038c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
32048c2ecf20Sopenharmony_ci	struct srp_target *target = iue->target;
32058c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = target->ldata;
32068c2ecf20Sopenharmony_ci	struct scatterlist *sgp;
32078c2ecf20Sopenharmony_ci	dma_addr_t client_ioba, server_ioba;
32088c2ecf20Sopenharmony_ci	ulong buf_len;
32098c2ecf20Sopenharmony_ci	ulong client_len, server_len;
32108c2ecf20Sopenharmony_ci	int md_idx;
32118c2ecf20Sopenharmony_ci	long tx_len;
32128c2ecf20Sopenharmony_ci	long rc = 0;
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	if (bytes == 0)
32158c2ecf20Sopenharmony_ci		return 0;
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	sgp = sg;
32188c2ecf20Sopenharmony_ci	client_len = 0;
32198c2ecf20Sopenharmony_ci	server_len = 0;
32208c2ecf20Sopenharmony_ci	md_idx = 0;
32218c2ecf20Sopenharmony_ci	tx_len = bytes;
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	do {
32248c2ecf20Sopenharmony_ci		if (client_len == 0) {
32258c2ecf20Sopenharmony_ci			if (md_idx >= nmd) {
32268c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "rdma: ran out of client memory descriptors\n");
32278c2ecf20Sopenharmony_ci				rc = -EIO;
32288c2ecf20Sopenharmony_ci				break;
32298c2ecf20Sopenharmony_ci			}
32308c2ecf20Sopenharmony_ci			client_ioba = be64_to_cpu(md[md_idx].va);
32318c2ecf20Sopenharmony_ci			client_len = be32_to_cpu(md[md_idx].len);
32328c2ecf20Sopenharmony_ci		}
32338c2ecf20Sopenharmony_ci		if (server_len == 0) {
32348c2ecf20Sopenharmony_ci			if (!sgp) {
32358c2ecf20Sopenharmony_ci				dev_err(&vscsi->dev, "rdma: ran out of scatter/gather list\n");
32368c2ecf20Sopenharmony_ci				rc = -EIO;
32378c2ecf20Sopenharmony_ci				break;
32388c2ecf20Sopenharmony_ci			}
32398c2ecf20Sopenharmony_ci			server_ioba = sg_dma_address(sgp);
32408c2ecf20Sopenharmony_ci			server_len = sg_dma_len(sgp);
32418c2ecf20Sopenharmony_ci		}
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci		buf_len = tx_len;
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci		if (buf_len > client_len)
32468c2ecf20Sopenharmony_ci			buf_len = client_len;
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci		if (buf_len > server_len)
32498c2ecf20Sopenharmony_ci			buf_len = server_len;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci		if (buf_len > max_vdma_size)
32528c2ecf20Sopenharmony_ci			buf_len = max_vdma_size;
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci		if (dir == DMA_TO_DEVICE) {
32558c2ecf20Sopenharmony_ci			/* read from client */
32568c2ecf20Sopenharmony_ci			rc = h_copy_rdma(buf_len,
32578c2ecf20Sopenharmony_ci					 vscsi->dds.window[REMOTE].liobn,
32588c2ecf20Sopenharmony_ci					 client_ioba,
32598c2ecf20Sopenharmony_ci					 vscsi->dds.window[LOCAL].liobn,
32608c2ecf20Sopenharmony_ci					 server_ioba);
32618c2ecf20Sopenharmony_ci		} else {
32628c2ecf20Sopenharmony_ci			/* The h_copy_rdma will cause phyp, running in another
32638c2ecf20Sopenharmony_ci			 * partition, to read memory, so we need to make sure
32648c2ecf20Sopenharmony_ci			 * the data has been written out, hence these syncs.
32658c2ecf20Sopenharmony_ci			 */
32668c2ecf20Sopenharmony_ci			/* ensure that everything is in memory */
32678c2ecf20Sopenharmony_ci			isync();
32688c2ecf20Sopenharmony_ci			/* ensure that memory has been made visible */
32698c2ecf20Sopenharmony_ci			dma_wmb();
32708c2ecf20Sopenharmony_ci			rc = h_copy_rdma(buf_len,
32718c2ecf20Sopenharmony_ci					 vscsi->dds.window[LOCAL].liobn,
32728c2ecf20Sopenharmony_ci					 server_ioba,
32738c2ecf20Sopenharmony_ci					 vscsi->dds.window[REMOTE].liobn,
32748c2ecf20Sopenharmony_ci					 client_ioba);
32758c2ecf20Sopenharmony_ci		}
32768c2ecf20Sopenharmony_ci		switch (rc) {
32778c2ecf20Sopenharmony_ci		case H_SUCCESS:
32788c2ecf20Sopenharmony_ci			break;
32798c2ecf20Sopenharmony_ci		case H_PERMISSION:
32808c2ecf20Sopenharmony_ci		case H_SOURCE_PARM:
32818c2ecf20Sopenharmony_ci		case H_DEST_PARM:
32828c2ecf20Sopenharmony_ci			if (connection_broken(vscsi)) {
32838c2ecf20Sopenharmony_ci				spin_lock_bh(&vscsi->intr_lock);
32848c2ecf20Sopenharmony_ci				vscsi->flags |=
32858c2ecf20Sopenharmony_ci					(RESPONSE_Q_DOWN | CLIENT_FAILED);
32868c2ecf20Sopenharmony_ci				spin_unlock_bh(&vscsi->intr_lock);
32878c2ecf20Sopenharmony_ci			}
32888c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "rdma: h_copy_rdma failed, rc %ld\n",
32898c2ecf20Sopenharmony_ci				rc);
32908c2ecf20Sopenharmony_ci			break;
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci		default:
32938c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "rdma: unknown error %ld from h_copy_rdma\n",
32948c2ecf20Sopenharmony_ci				rc);
32958c2ecf20Sopenharmony_ci			break;
32968c2ecf20Sopenharmony_ci		}
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci		if (!rc) {
32998c2ecf20Sopenharmony_ci			tx_len -= buf_len;
33008c2ecf20Sopenharmony_ci			if (tx_len) {
33018c2ecf20Sopenharmony_ci				client_len -= buf_len;
33028c2ecf20Sopenharmony_ci				if (client_len == 0)
33038c2ecf20Sopenharmony_ci					md_idx++;
33048c2ecf20Sopenharmony_ci				else
33058c2ecf20Sopenharmony_ci					client_ioba += buf_len;
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci				server_len -= buf_len;
33088c2ecf20Sopenharmony_ci				if (server_len == 0)
33098c2ecf20Sopenharmony_ci					sgp = sg_next(sgp);
33108c2ecf20Sopenharmony_ci				else
33118c2ecf20Sopenharmony_ci					server_ioba += buf_len;
33128c2ecf20Sopenharmony_ci			} else {
33138c2ecf20Sopenharmony_ci				break;
33148c2ecf20Sopenharmony_ci			}
33158c2ecf20Sopenharmony_ci		}
33168c2ecf20Sopenharmony_ci	} while (!rc);
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci	return rc;
33198c2ecf20Sopenharmony_ci}
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci/**
33228c2ecf20Sopenharmony_ci * ibmvscsis_handle_crq() - Handle CRQ
33238c2ecf20Sopenharmony_ci * @data:	Pointer to our adapter structure
33248c2ecf20Sopenharmony_ci *
33258c2ecf20Sopenharmony_ci * Read the command elements from the command queue and copy the payloads
33268c2ecf20Sopenharmony_ci * associated with the command elements to local memory and execute the
33278c2ecf20Sopenharmony_ci * SRP requests.
33288c2ecf20Sopenharmony_ci *
33298c2ecf20Sopenharmony_ci * Note: this is an edge triggered interrupt. It can not be shared.
33308c2ecf20Sopenharmony_ci */
33318c2ecf20Sopenharmony_cistatic void ibmvscsis_handle_crq(unsigned long data)
33328c2ecf20Sopenharmony_ci{
33338c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = (struct scsi_info *)data;
33348c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
33358c2ecf20Sopenharmony_ci	long rc;
33368c2ecf20Sopenharmony_ci	bool ack = true;
33378c2ecf20Sopenharmony_ci	volatile u8 valid;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "got interrupt\n");
33428c2ecf20Sopenharmony_ci
33438c2ecf20Sopenharmony_ci	/*
33448c2ecf20Sopenharmony_ci	 * if we are in a path where we are waiting for all pending commands
33458c2ecf20Sopenharmony_ci	 * to complete because we received a transport event and anything in
33468c2ecf20Sopenharmony_ci	 * the command queue is for a new connection, do nothing
33478c2ecf20Sopenharmony_ci	 */
33488c2ecf20Sopenharmony_ci	if (TARGET_STOP(vscsi)) {
33498c2ecf20Sopenharmony_ci		vio_enable_interrupts(vscsi->dma_dev);
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "handle_crq, don't process: flags 0x%x, state 0x%hx\n",
33528c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state);
33538c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
33548c2ecf20Sopenharmony_ci		return;
33558c2ecf20Sopenharmony_ci	}
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci	rc = vscsi->flags & SCHEDULE_DISCONNECT;
33588c2ecf20Sopenharmony_ci	crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
33598c2ecf20Sopenharmony_ci	valid = crq->valid;
33608c2ecf20Sopenharmony_ci	dma_rmb();
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci	while (valid) {
33638c2ecf20Sopenharmony_ci		/*
33648c2ecf20Sopenharmony_ci		 * These are edege triggered interrupts. After dropping out of
33658c2ecf20Sopenharmony_ci		 * the while loop, the code must check for work since an
33668c2ecf20Sopenharmony_ci		 * interrupt could be lost, and an elment be left on the queue,
33678c2ecf20Sopenharmony_ci		 * hence the label.
33688c2ecf20Sopenharmony_ci		 */
33698c2ecf20Sopenharmony_cicmd_work:
33708c2ecf20Sopenharmony_ci		vscsi->cmd_q.index =
33718c2ecf20Sopenharmony_ci			(vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci		if (!rc) {
33748c2ecf20Sopenharmony_ci			rc = ibmvscsis_parse_command(vscsi, crq);
33758c2ecf20Sopenharmony_ci		} else {
33768c2ecf20Sopenharmony_ci			if ((uint)crq->valid == VALID_TRANS_EVENT) {
33778c2ecf20Sopenharmony_ci				/*
33788c2ecf20Sopenharmony_ci				 * must service the transport layer events even
33798c2ecf20Sopenharmony_ci				 * in an error state, dont break out until all
33808c2ecf20Sopenharmony_ci				 * the consecutive transport events have been
33818c2ecf20Sopenharmony_ci				 * processed
33828c2ecf20Sopenharmony_ci				 */
33838c2ecf20Sopenharmony_ci				rc = ibmvscsis_trans_event(vscsi, crq);
33848c2ecf20Sopenharmony_ci			} else if (vscsi->flags & TRANS_EVENT) {
33858c2ecf20Sopenharmony_ci				/*
33868c2ecf20Sopenharmony_ci				 * if a transport event has occurred leave
33878c2ecf20Sopenharmony_ci				 * everything but transport events on the queue
33888c2ecf20Sopenharmony_ci				 *
33898c2ecf20Sopenharmony_ci				 * need to decrement the queue index so we can
33908c2ecf20Sopenharmony_ci				 * look at the element again
33918c2ecf20Sopenharmony_ci				 */
33928c2ecf20Sopenharmony_ci				if (vscsi->cmd_q.index)
33938c2ecf20Sopenharmony_ci					vscsi->cmd_q.index -= 1;
33948c2ecf20Sopenharmony_ci				else
33958c2ecf20Sopenharmony_ci					/*
33968c2ecf20Sopenharmony_ci					 * index is at 0 it just wrapped.
33978c2ecf20Sopenharmony_ci					 * have it index last element in q
33988c2ecf20Sopenharmony_ci					 */
33998c2ecf20Sopenharmony_ci					vscsi->cmd_q.index = vscsi->cmd_q.mask;
34008c2ecf20Sopenharmony_ci				break;
34018c2ecf20Sopenharmony_ci			}
34028c2ecf20Sopenharmony_ci		}
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci		crq->valid = INVALIDATE_CMD_RESP_EL;
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci		crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
34078c2ecf20Sopenharmony_ci		valid = crq->valid;
34088c2ecf20Sopenharmony_ci		dma_rmb();
34098c2ecf20Sopenharmony_ci	}
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_ci	if (!rc) {
34128c2ecf20Sopenharmony_ci		if (ack) {
34138c2ecf20Sopenharmony_ci			vio_enable_interrupts(vscsi->dma_dev);
34148c2ecf20Sopenharmony_ci			ack = false;
34158c2ecf20Sopenharmony_ci			dev_dbg(&vscsi->dev, "handle_crq, reenabling interrupts\n");
34168c2ecf20Sopenharmony_ci		}
34178c2ecf20Sopenharmony_ci		valid = crq->valid;
34188c2ecf20Sopenharmony_ci		dma_rmb();
34198c2ecf20Sopenharmony_ci		if (valid)
34208c2ecf20Sopenharmony_ci			goto cmd_work;
34218c2ecf20Sopenharmony_ci	} else {
34228c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "handle_crq, error: flags 0x%x, state 0x%hx, crq index 0x%x\n",
34238c2ecf20Sopenharmony_ci			vscsi->flags, vscsi->state, vscsi->cmd_q.index);
34248c2ecf20Sopenharmony_ci	}
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Leaving handle_crq: schedule_q empty %d, flags 0x%x, state 0x%hx\n",
34278c2ecf20Sopenharmony_ci		(int)list_empty(&vscsi->schedule_q), vscsi->flags,
34288c2ecf20Sopenharmony_ci		vscsi->state);
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
34318c2ecf20Sopenharmony_ci}
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_cistatic int ibmvscsis_probe(struct vio_dev *vdev,
34348c2ecf20Sopenharmony_ci			   const struct vio_device_id *id)
34358c2ecf20Sopenharmony_ci{
34368c2ecf20Sopenharmony_ci	struct scsi_info *vscsi;
34378c2ecf20Sopenharmony_ci	int rc = 0;
34388c2ecf20Sopenharmony_ci	long hrc = 0;
34398c2ecf20Sopenharmony_ci	char wq_name[24];
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL);
34428c2ecf20Sopenharmony_ci	if (!vscsi) {
34438c2ecf20Sopenharmony_ci		rc = -ENOMEM;
34448c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "probe: allocation of adapter failed\n");
34458c2ecf20Sopenharmony_ci		return rc;
34468c2ecf20Sopenharmony_ci	}
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	vscsi->dma_dev = vdev;
34498c2ecf20Sopenharmony_ci	vscsi->dev = vdev->dev;
34508c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vscsi->schedule_q);
34518c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vscsi->waiting_rsp);
34528c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vscsi->active_q);
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci	snprintf(vscsi->tport.tport_name, IBMVSCSIS_NAMELEN, "%s",
34558c2ecf20Sopenharmony_ci		 dev_name(&vdev->dev));
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "probe tport_name: %s\n", vscsi->tport.tport_name);
34588c2ecf20Sopenharmony_ci
34598c2ecf20Sopenharmony_ci	rc = read_dma_window(vscsi);
34608c2ecf20Sopenharmony_ci	if (rc)
34618c2ecf20Sopenharmony_ci		goto free_adapter;
34628c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "Probe: liobn 0x%x, riobn 0x%x\n",
34638c2ecf20Sopenharmony_ci		vscsi->dds.window[LOCAL].liobn,
34648c2ecf20Sopenharmony_ci		vscsi->dds.window[REMOTE].liobn);
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	snprintf(vscsi->eye, sizeof(vscsi->eye), "VSCSI %s", vdev->name);
34678c2ecf20Sopenharmony_ci
34688c2ecf20Sopenharmony_ci	vscsi->dds.unit_id = vdev->unit_address;
34698c2ecf20Sopenharmony_ci	strscpy(vscsi->dds.partition_name, partition_name,
34708c2ecf20Sopenharmony_ci		sizeof(vscsi->dds.partition_name));
34718c2ecf20Sopenharmony_ci	vscsi->dds.partition_num = partition_number;
34728c2ecf20Sopenharmony_ci
34738c2ecf20Sopenharmony_ci	spin_lock_bh(&ibmvscsis_dev_lock);
34748c2ecf20Sopenharmony_ci	list_add_tail(&vscsi->list, &ibmvscsis_dev_list);
34758c2ecf20Sopenharmony_ci	spin_unlock_bh(&ibmvscsis_dev_lock);
34768c2ecf20Sopenharmony_ci
34778c2ecf20Sopenharmony_ci	/*
34788c2ecf20Sopenharmony_ci	 * TBD: How do we determine # of cmds to request?  Do we know how
34798c2ecf20Sopenharmony_ci	 * many "children" we have?
34808c2ecf20Sopenharmony_ci	 */
34818c2ecf20Sopenharmony_ci	vscsi->request_limit = INITIAL_SRP_LIMIT;
34828c2ecf20Sopenharmony_ci	rc = srp_target_alloc(&vscsi->target, &vdev->dev, vscsi->request_limit,
34838c2ecf20Sopenharmony_ci			      SRP_MAX_IU_LEN);
34848c2ecf20Sopenharmony_ci	if (rc)
34858c2ecf20Sopenharmony_ci		goto rem_list;
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_ci	vscsi->target.ldata = vscsi;
34888c2ecf20Sopenharmony_ci
34898c2ecf20Sopenharmony_ci	rc = ibmvscsis_alloc_cmds(vscsi, vscsi->request_limit);
34908c2ecf20Sopenharmony_ci	if (rc) {
34918c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "alloc_cmds failed, rc %d, num %d\n",
34928c2ecf20Sopenharmony_ci			rc, vscsi->request_limit);
34938c2ecf20Sopenharmony_ci		goto free_target;
34948c2ecf20Sopenharmony_ci	}
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	/*
34978c2ecf20Sopenharmony_ci	 * Note: the lock is used in freeing timers, so must initialize
34988c2ecf20Sopenharmony_ci	 * first so that ordering in case of error is correct.
34998c2ecf20Sopenharmony_ci	 */
35008c2ecf20Sopenharmony_ci	spin_lock_init(&vscsi->intr_lock);
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci	rc = ibmvscsis_alloctimer(vscsi);
35038c2ecf20Sopenharmony_ci	if (rc) {
35048c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "probe: alloctimer failed, rc %d\n", rc);
35058c2ecf20Sopenharmony_ci		goto free_cmds;
35068c2ecf20Sopenharmony_ci	}
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci	rc = ibmvscsis_create_command_q(vscsi, 256);
35098c2ecf20Sopenharmony_ci	if (rc) {
35108c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "probe: create_command_q failed, rc %d\n",
35118c2ecf20Sopenharmony_ci			rc);
35128c2ecf20Sopenharmony_ci		goto free_timer;
35138c2ecf20Sopenharmony_ci	}
35148c2ecf20Sopenharmony_ci
35158c2ecf20Sopenharmony_ci	vscsi->map_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
35168c2ecf20Sopenharmony_ci	if (!vscsi->map_buf) {
35178c2ecf20Sopenharmony_ci		rc = -ENOMEM;
35188c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "probe: allocating cmd buffer failed\n");
35198c2ecf20Sopenharmony_ci		goto destroy_queue;
35208c2ecf20Sopenharmony_ci	}
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci	vscsi->map_ioba = dma_map_single(&vdev->dev, vscsi->map_buf, PAGE_SIZE,
35238c2ecf20Sopenharmony_ci					 DMA_BIDIRECTIONAL);
35248c2ecf20Sopenharmony_ci	if (dma_mapping_error(&vdev->dev, vscsi->map_ioba)) {
35258c2ecf20Sopenharmony_ci		rc = -ENOMEM;
35268c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "probe: error mapping command buffer\n");
35278c2ecf20Sopenharmony_ci		goto free_buf;
35288c2ecf20Sopenharmony_ci	}
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci	hrc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
35318c2ecf20Sopenharmony_ci		       (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
35328c2ecf20Sopenharmony_ci		       0);
35338c2ecf20Sopenharmony_ci	if (hrc == H_SUCCESS)
35348c2ecf20Sopenharmony_ci		vscsi->client_data.partition_number =
35358c2ecf20Sopenharmony_ci			be64_to_cpu(*(u64 *)vscsi->map_buf);
35368c2ecf20Sopenharmony_ci	/*
35378c2ecf20Sopenharmony_ci	 * We expect the VIOCTL to fail if we're configured as "any
35388c2ecf20Sopenharmony_ci	 * client can connect" and the client isn't activated yet.
35398c2ecf20Sopenharmony_ci	 * We'll make the call again when he sends an init msg.
35408c2ecf20Sopenharmony_ci	 */
35418c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "probe hrc %ld, client partition num %d\n",
35428c2ecf20Sopenharmony_ci		hrc, vscsi->client_data.partition_number);
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	tasklet_init(&vscsi->work_task, ibmvscsis_handle_crq,
35458c2ecf20Sopenharmony_ci		     (unsigned long)vscsi);
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	init_completion(&vscsi->wait_idle);
35488c2ecf20Sopenharmony_ci	init_completion(&vscsi->unconfig);
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_ci	snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev));
35518c2ecf20Sopenharmony_ci	vscsi->work_q = create_workqueue(wq_name);
35528c2ecf20Sopenharmony_ci	if (!vscsi->work_q) {
35538c2ecf20Sopenharmony_ci		rc = -ENOMEM;
35548c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "create_workqueue failed\n");
35558c2ecf20Sopenharmony_ci		goto unmap_buf;
35568c2ecf20Sopenharmony_ci	}
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci	rc = request_irq(vdev->irq, ibmvscsis_interrupt, 0, "ibmvscsis", vscsi);
35598c2ecf20Sopenharmony_ci	if (rc) {
35608c2ecf20Sopenharmony_ci		rc = -EPERM;
35618c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "probe: request_irq failed, rc %d\n", rc);
35628c2ecf20Sopenharmony_ci		goto destroy_WQ;
35638c2ecf20Sopenharmony_ci	}
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci	vscsi->state = WAIT_ENABLED;
35668c2ecf20Sopenharmony_ci
35678c2ecf20Sopenharmony_ci	dev_set_drvdata(&vdev->dev, vscsi);
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_ci	return 0;
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_cidestroy_WQ:
35728c2ecf20Sopenharmony_ci	destroy_workqueue(vscsi->work_q);
35738c2ecf20Sopenharmony_ciunmap_buf:
35748c2ecf20Sopenharmony_ci	dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
35758c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
35768c2ecf20Sopenharmony_cifree_buf:
35778c2ecf20Sopenharmony_ci	kfree(vscsi->map_buf);
35788c2ecf20Sopenharmony_cidestroy_queue:
35798c2ecf20Sopenharmony_ci	tasklet_kill(&vscsi->work_task);
35808c2ecf20Sopenharmony_ci	ibmvscsis_unregister_command_q(vscsi);
35818c2ecf20Sopenharmony_ci	ibmvscsis_destroy_command_q(vscsi);
35828c2ecf20Sopenharmony_cifree_timer:
35838c2ecf20Sopenharmony_ci	ibmvscsis_freetimer(vscsi);
35848c2ecf20Sopenharmony_cifree_cmds:
35858c2ecf20Sopenharmony_ci	ibmvscsis_free_cmds(vscsi);
35868c2ecf20Sopenharmony_cifree_target:
35878c2ecf20Sopenharmony_ci	srp_target_free(&vscsi->target);
35888c2ecf20Sopenharmony_cirem_list:
35898c2ecf20Sopenharmony_ci	spin_lock_bh(&ibmvscsis_dev_lock);
35908c2ecf20Sopenharmony_ci	list_del(&vscsi->list);
35918c2ecf20Sopenharmony_ci	spin_unlock_bh(&ibmvscsis_dev_lock);
35928c2ecf20Sopenharmony_cifree_adapter:
35938c2ecf20Sopenharmony_ci	kfree(vscsi);
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	return rc;
35968c2ecf20Sopenharmony_ci}
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_cistatic int ibmvscsis_remove(struct vio_dev *vdev)
35998c2ecf20Sopenharmony_ci{
36008c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = dev_get_drvdata(&vdev->dev);
36018c2ecf20Sopenharmony_ci
36028c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "remove (%s)\n", dev_name(&vscsi->dma_dev->dev));
36038c2ecf20Sopenharmony_ci
36048c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
36058c2ecf20Sopenharmony_ci	ibmvscsis_post_disconnect(vscsi, UNCONFIGURING, 0);
36068c2ecf20Sopenharmony_ci	vscsi->flags |= CFG_SLEEPING;
36078c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
36088c2ecf20Sopenharmony_ci	wait_for_completion(&vscsi->unconfig);
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	vio_disable_interrupts(vdev);
36118c2ecf20Sopenharmony_ci	free_irq(vdev->irq, vscsi);
36128c2ecf20Sopenharmony_ci	destroy_workqueue(vscsi->work_q);
36138c2ecf20Sopenharmony_ci	dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
36148c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
36158c2ecf20Sopenharmony_ci	kfree(vscsi->map_buf);
36168c2ecf20Sopenharmony_ci	tasklet_kill(&vscsi->work_task);
36178c2ecf20Sopenharmony_ci	ibmvscsis_destroy_command_q(vscsi);
36188c2ecf20Sopenharmony_ci	ibmvscsis_freetimer(vscsi);
36198c2ecf20Sopenharmony_ci	ibmvscsis_free_cmds(vscsi);
36208c2ecf20Sopenharmony_ci	srp_target_free(&vscsi->target);
36218c2ecf20Sopenharmony_ci	spin_lock_bh(&ibmvscsis_dev_lock);
36228c2ecf20Sopenharmony_ci	list_del(&vscsi->list);
36238c2ecf20Sopenharmony_ci	spin_unlock_bh(&ibmvscsis_dev_lock);
36248c2ecf20Sopenharmony_ci	kfree(vscsi);
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci	return 0;
36278c2ecf20Sopenharmony_ci}
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_cistatic ssize_t system_id_show(struct device *dev,
36308c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
36318c2ecf20Sopenharmony_ci{
36328c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
36338c2ecf20Sopenharmony_ci}
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_cistatic ssize_t partition_number_show(struct device *dev,
36368c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
36378c2ecf20Sopenharmony_ci{
36388c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
36398c2ecf20Sopenharmony_ci}
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_cistatic ssize_t unit_address_show(struct device *dev,
36428c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
36438c2ecf20Sopenharmony_ci{
36448c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(dev, struct scsi_info, dev);
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%x\n", vscsi->dma_dev->unit_address);
36478c2ecf20Sopenharmony_ci}
36488c2ecf20Sopenharmony_ci
36498c2ecf20Sopenharmony_cistatic int ibmvscsis_get_system_info(void)
36508c2ecf20Sopenharmony_ci{
36518c2ecf20Sopenharmony_ci	struct device_node *rootdn, *vdevdn;
36528c2ecf20Sopenharmony_ci	const char *id, *model, *name;
36538c2ecf20Sopenharmony_ci	const uint *num;
36548c2ecf20Sopenharmony_ci
36558c2ecf20Sopenharmony_ci	rootdn = of_find_node_by_path("/");
36568c2ecf20Sopenharmony_ci	if (!rootdn)
36578c2ecf20Sopenharmony_ci		return -ENOENT;
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci	model = of_get_property(rootdn, "model", NULL);
36608c2ecf20Sopenharmony_ci	id = of_get_property(rootdn, "system-id", NULL);
36618c2ecf20Sopenharmony_ci	if (model && id)
36628c2ecf20Sopenharmony_ci		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	name = of_get_property(rootdn, "ibm,partition-name", NULL);
36658c2ecf20Sopenharmony_ci	if (name)
36668c2ecf20Sopenharmony_ci		strncpy(partition_name, name, sizeof(partition_name));
36678c2ecf20Sopenharmony_ci
36688c2ecf20Sopenharmony_ci	num = of_get_property(rootdn, "ibm,partition-no", NULL);
36698c2ecf20Sopenharmony_ci	if (num)
36708c2ecf20Sopenharmony_ci		partition_number = of_read_number(num, 1);
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_ci	of_node_put(rootdn);
36738c2ecf20Sopenharmony_ci
36748c2ecf20Sopenharmony_ci	vdevdn = of_find_node_by_path("/vdevice");
36758c2ecf20Sopenharmony_ci	if (vdevdn) {
36768c2ecf20Sopenharmony_ci		const uint *mvds;
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci		mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
36798c2ecf20Sopenharmony_ci				       NULL);
36808c2ecf20Sopenharmony_ci		if (mvds)
36818c2ecf20Sopenharmony_ci			max_vdma_size = *mvds;
36828c2ecf20Sopenharmony_ci		of_node_put(vdevdn);
36838c2ecf20Sopenharmony_ci	}
36848c2ecf20Sopenharmony_ci
36858c2ecf20Sopenharmony_ci	return 0;
36868c2ecf20Sopenharmony_ci}
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_cistatic char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
36898c2ecf20Sopenharmony_ci{
36908c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport =
36918c2ecf20Sopenharmony_ci		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci	return tport->tport_name;
36948c2ecf20Sopenharmony_ci}
36958c2ecf20Sopenharmony_ci
36968c2ecf20Sopenharmony_cistatic u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
36978c2ecf20Sopenharmony_ci{
36988c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport =
36998c2ecf20Sopenharmony_ci		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
37008c2ecf20Sopenharmony_ci
37018c2ecf20Sopenharmony_ci	return tport->tport_tpgt;
37028c2ecf20Sopenharmony_ci}
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_cistatic u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
37058c2ecf20Sopenharmony_ci{
37068c2ecf20Sopenharmony_ci	return 1;
37078c2ecf20Sopenharmony_ci}
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_cistatic int ibmvscsis_check_true(struct se_portal_group *se_tpg)
37108c2ecf20Sopenharmony_ci{
37118c2ecf20Sopenharmony_ci	return 1;
37128c2ecf20Sopenharmony_ci}
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_cistatic int ibmvscsis_check_false(struct se_portal_group *se_tpg)
37158c2ecf20Sopenharmony_ci{
37168c2ecf20Sopenharmony_ci	return 0;
37178c2ecf20Sopenharmony_ci}
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_cistatic u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
37208c2ecf20Sopenharmony_ci{
37218c2ecf20Sopenharmony_ci	return 1;
37228c2ecf20Sopenharmony_ci}
37238c2ecf20Sopenharmony_ci
37248c2ecf20Sopenharmony_cistatic int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
37258c2ecf20Sopenharmony_ci{
37268c2ecf20Sopenharmony_ci	return target_put_sess_cmd(se_cmd);
37278c2ecf20Sopenharmony_ci}
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_cistatic void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
37308c2ecf20Sopenharmony_ci{
37318c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
37328c2ecf20Sopenharmony_ci						 se_cmd);
37338c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci	spin_lock_bh(&vscsi->intr_lock);
37368c2ecf20Sopenharmony_ci	/* Remove from active_q */
37378c2ecf20Sopenharmony_ci	list_move_tail(&cmd->list, &vscsi->waiting_rsp);
37388c2ecf20Sopenharmony_ci	ibmvscsis_send_messages(vscsi);
37398c2ecf20Sopenharmony_ci	spin_unlock_bh(&vscsi->intr_lock);
37408c2ecf20Sopenharmony_ci}
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_cistatic u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
37438c2ecf20Sopenharmony_ci{
37448c2ecf20Sopenharmony_ci	return 0;
37458c2ecf20Sopenharmony_ci}
37468c2ecf20Sopenharmony_ci
37478c2ecf20Sopenharmony_cistatic int ibmvscsis_write_pending(struct se_cmd *se_cmd)
37488c2ecf20Sopenharmony_ci{
37498c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
37508c2ecf20Sopenharmony_ci						 se_cmd);
37518c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
37528c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
37538c2ecf20Sopenharmony_ci	int rc;
37548c2ecf20Sopenharmony_ci
37558c2ecf20Sopenharmony_ci	/*
37568c2ecf20Sopenharmony_ci	 * If CLIENT_FAILED OR RESPONSE_Q_DOWN, then just return success
37578c2ecf20Sopenharmony_ci	 * since LIO can't do anything about it, and we dont want to
37588c2ecf20Sopenharmony_ci	 * attempt an srp_transfer_data.
37598c2ecf20Sopenharmony_ci	 */
37608c2ecf20Sopenharmony_ci	if ((vscsi->flags & (CLIENT_FAILED | RESPONSE_Q_DOWN))) {
37618c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "write_pending failed since: %d\n",
37628c2ecf20Sopenharmony_ci			vscsi->flags);
37638c2ecf20Sopenharmony_ci		return -EIO;
37648c2ecf20Sopenharmony_ci
37658c2ecf20Sopenharmony_ci	}
37668c2ecf20Sopenharmony_ci
37678c2ecf20Sopenharmony_ci	rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma,
37688c2ecf20Sopenharmony_ci			       1, 1);
37698c2ecf20Sopenharmony_ci	if (rc) {
37708c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "srp_transfer_data() failed: %d\n", rc);
37718c2ecf20Sopenharmony_ci		return -EIO;
37728c2ecf20Sopenharmony_ci	}
37738c2ecf20Sopenharmony_ci	/*
37748c2ecf20Sopenharmony_ci	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
37758c2ecf20Sopenharmony_ci	 * object execution queue.
37768c2ecf20Sopenharmony_ci	 */
37778c2ecf20Sopenharmony_ci	target_execute_cmd(se_cmd);
37788c2ecf20Sopenharmony_ci	return 0;
37798c2ecf20Sopenharmony_ci}
37808c2ecf20Sopenharmony_ci
37818c2ecf20Sopenharmony_cistatic void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
37828c2ecf20Sopenharmony_ci{
37838c2ecf20Sopenharmony_ci}
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_cistatic int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
37868c2ecf20Sopenharmony_ci{
37878c2ecf20Sopenharmony_ci	return 0;
37888c2ecf20Sopenharmony_ci}
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_cistatic int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
37918c2ecf20Sopenharmony_ci{
37928c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
37938c2ecf20Sopenharmony_ci						 se_cmd);
37948c2ecf20Sopenharmony_ci	struct iu_entry *iue = cmd->iue;
37958c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
37968c2ecf20Sopenharmony_ci	uint len = 0;
37978c2ecf20Sopenharmony_ci	int rc;
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_ci	rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma, 1,
38008c2ecf20Sopenharmony_ci			       1);
38018c2ecf20Sopenharmony_ci	if (rc) {
38028c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "srp_transfer_data failed: %d\n", rc);
38038c2ecf20Sopenharmony_ci		se_cmd->scsi_sense_length = 18;
38048c2ecf20Sopenharmony_ci		memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
38058c2ecf20Sopenharmony_ci		/* Logical Unit Communication Time-out asc/ascq = 0x0801 */
38068c2ecf20Sopenharmony_ci		scsi_build_sense_buffer(0, se_cmd->sense_buffer, MEDIUM_ERROR,
38078c2ecf20Sopenharmony_ci					0x08, 0x01);
38088c2ecf20Sopenharmony_ci	}
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci	srp_build_response(vscsi, cmd, &len);
38118c2ecf20Sopenharmony_ci	cmd->rsp.format = SRP_FORMAT;
38128c2ecf20Sopenharmony_ci	cmd->rsp.len = len;
38138c2ecf20Sopenharmony_ci
38148c2ecf20Sopenharmony_ci	return 0;
38158c2ecf20Sopenharmony_ci}
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_cistatic int ibmvscsis_queue_status(struct se_cmd *se_cmd)
38188c2ecf20Sopenharmony_ci{
38198c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
38208c2ecf20Sopenharmony_ci						 se_cmd);
38218c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
38228c2ecf20Sopenharmony_ci	uint len;
38238c2ecf20Sopenharmony_ci
38248c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "queue_status %p\n", se_cmd);
38258c2ecf20Sopenharmony_ci
38268c2ecf20Sopenharmony_ci	srp_build_response(vscsi, cmd, &len);
38278c2ecf20Sopenharmony_ci	cmd->rsp.format = SRP_FORMAT;
38288c2ecf20Sopenharmony_ci	cmd->rsp.len = len;
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	return 0;
38318c2ecf20Sopenharmony_ci}
38328c2ecf20Sopenharmony_ci
38338c2ecf20Sopenharmony_cistatic void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
38348c2ecf20Sopenharmony_ci{
38358c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
38368c2ecf20Sopenharmony_ci						 se_cmd);
38378c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
38388c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd_itr;
38398c2ecf20Sopenharmony_ci	struct iu_entry *iue = iue = cmd->iue;
38408c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
38418c2ecf20Sopenharmony_ci	u64 tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
38428c2ecf20Sopenharmony_ci	uint len;
38438c2ecf20Sopenharmony_ci
38448c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "queue_tm_rsp %p, status %d\n",
38458c2ecf20Sopenharmony_ci		se_cmd, (int)se_cmd->se_tmr_req->response);
38468c2ecf20Sopenharmony_ci
38478c2ecf20Sopenharmony_ci	if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK &&
38488c2ecf20Sopenharmony_ci	    cmd->se_cmd.se_tmr_req->response == TMR_TASK_DOES_NOT_EXIST) {
38498c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
38508c2ecf20Sopenharmony_ci		list_for_each_entry(cmd_itr, &vscsi->active_q, list) {
38518c2ecf20Sopenharmony_ci			if (tag_to_abort == cmd_itr->se_cmd.tag) {
38528c2ecf20Sopenharmony_ci				cmd_itr->abort_cmd = cmd;
38538c2ecf20Sopenharmony_ci				cmd->flags |= DELAY_SEND;
38548c2ecf20Sopenharmony_ci				break;
38558c2ecf20Sopenharmony_ci			}
38568c2ecf20Sopenharmony_ci		}
38578c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
38588c2ecf20Sopenharmony_ci	}
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_ci	srp_build_response(vscsi, cmd, &len);
38618c2ecf20Sopenharmony_ci	cmd->rsp.format = SRP_FORMAT;
38628c2ecf20Sopenharmony_ci	cmd->rsp.len = len;
38638c2ecf20Sopenharmony_ci}
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_cistatic void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
38668c2ecf20Sopenharmony_ci{
38678c2ecf20Sopenharmony_ci	struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
38688c2ecf20Sopenharmony_ci						 se_cmd);
38698c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = cmd->adapter;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "ibmvscsis_aborted_task %p task_tag: %llu\n",
38728c2ecf20Sopenharmony_ci		se_cmd, se_cmd->tag);
38738c2ecf20Sopenharmony_ci}
38748c2ecf20Sopenharmony_ci
38758c2ecf20Sopenharmony_cistatic struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
38768c2ecf20Sopenharmony_ci					   struct config_group *group,
38778c2ecf20Sopenharmony_ci					   const char *name)
38788c2ecf20Sopenharmony_ci{
38798c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport;
38808c2ecf20Sopenharmony_ci	struct scsi_info *vscsi;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci	tport = ibmvscsis_lookup_port(name);
38838c2ecf20Sopenharmony_ci	if (tport) {
38848c2ecf20Sopenharmony_ci		vscsi = container_of(tport, struct scsi_info, tport);
38858c2ecf20Sopenharmony_ci		tport->tport_proto_id = SCSI_PROTOCOL_SRP;
38868c2ecf20Sopenharmony_ci		dev_dbg(&vscsi->dev, "make_tport(%s), pointer:%p, tport_id:%x\n",
38878c2ecf20Sopenharmony_ci			name, tport, tport->tport_proto_id);
38888c2ecf20Sopenharmony_ci		return &tport->tport_wwn;
38898c2ecf20Sopenharmony_ci	}
38908c2ecf20Sopenharmony_ci
38918c2ecf20Sopenharmony_ci	return ERR_PTR(-EINVAL);
38928c2ecf20Sopenharmony_ci}
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_cistatic void ibmvscsis_drop_tport(struct se_wwn *wwn)
38958c2ecf20Sopenharmony_ci{
38968c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport = container_of(wwn,
38978c2ecf20Sopenharmony_ci						     struct ibmvscsis_tport,
38988c2ecf20Sopenharmony_ci						     tport_wwn);
38998c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport);
39008c2ecf20Sopenharmony_ci
39018c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "drop_tport(%s)\n",
39028c2ecf20Sopenharmony_ci		config_item_name(&tport->tport_wwn.wwn_group.cg_item));
39038c2ecf20Sopenharmony_ci}
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_cistatic struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
39068c2ecf20Sopenharmony_ci						  const char *name)
39078c2ecf20Sopenharmony_ci{
39088c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport =
39098c2ecf20Sopenharmony_ci		container_of(wwn, struct ibmvscsis_tport, tport_wwn);
39108c2ecf20Sopenharmony_ci	u16 tpgt;
39118c2ecf20Sopenharmony_ci	int rc;
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci	if (strstr(name, "tpgt_") != name)
39148c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
39158c2ecf20Sopenharmony_ci	rc = kstrtou16(name + 5, 0, &tpgt);
39168c2ecf20Sopenharmony_ci	if (rc)
39178c2ecf20Sopenharmony_ci		return ERR_PTR(rc);
39188c2ecf20Sopenharmony_ci	tport->tport_tpgt = tpgt;
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_ci	tport->releasing = false;
39218c2ecf20Sopenharmony_ci
39228c2ecf20Sopenharmony_ci	rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg,
39238c2ecf20Sopenharmony_ci			       tport->tport_proto_id);
39248c2ecf20Sopenharmony_ci	if (rc)
39258c2ecf20Sopenharmony_ci		return ERR_PTR(rc);
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	return &tport->se_tpg;
39288c2ecf20Sopenharmony_ci}
39298c2ecf20Sopenharmony_ci
39308c2ecf20Sopenharmony_cistatic void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
39318c2ecf20Sopenharmony_ci{
39328c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport = container_of(se_tpg,
39338c2ecf20Sopenharmony_ci						     struct ibmvscsis_tport,
39348c2ecf20Sopenharmony_ci						     se_tpg);
39358c2ecf20Sopenharmony_ci
39368c2ecf20Sopenharmony_ci	tport->releasing = true;
39378c2ecf20Sopenharmony_ci	tport->enabled = false;
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci	/*
39408c2ecf20Sopenharmony_ci	 * Release the virtual I_T Nexus for this ibmvscsis TPG
39418c2ecf20Sopenharmony_ci	 */
39428c2ecf20Sopenharmony_ci	ibmvscsis_drop_nexus(tport);
39438c2ecf20Sopenharmony_ci	/*
39448c2ecf20Sopenharmony_ci	 * Deregister the se_tpg from TCM..
39458c2ecf20Sopenharmony_ci	 */
39468c2ecf20Sopenharmony_ci	core_tpg_deregister(se_tpg);
39478c2ecf20Sopenharmony_ci}
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_cistatic ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
39508c2ecf20Sopenharmony_ci					  char *page)
39518c2ecf20Sopenharmony_ci{
39528c2ecf20Sopenharmony_ci	return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
39538c2ecf20Sopenharmony_ci}
39548c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_cistatic struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
39578c2ecf20Sopenharmony_ci	&ibmvscsis_wwn_attr_version,
39588c2ecf20Sopenharmony_ci	NULL,
39598c2ecf20Sopenharmony_ci};
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_cistatic ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
39628c2ecf20Sopenharmony_ci					 char *page)
39638c2ecf20Sopenharmony_ci{
39648c2ecf20Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
39658c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport = container_of(se_tpg,
39668c2ecf20Sopenharmony_ci						     struct ibmvscsis_tport,
39678c2ecf20Sopenharmony_ci						     se_tpg);
39688c2ecf20Sopenharmony_ci
39698c2ecf20Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
39708c2ecf20Sopenharmony_ci}
39718c2ecf20Sopenharmony_ci
39728c2ecf20Sopenharmony_cistatic ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
39738c2ecf20Sopenharmony_ci					  const char *page, size_t count)
39748c2ecf20Sopenharmony_ci{
39758c2ecf20Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
39768c2ecf20Sopenharmony_ci	struct ibmvscsis_tport *tport = container_of(se_tpg,
39778c2ecf20Sopenharmony_ci						     struct ibmvscsis_tport,
39788c2ecf20Sopenharmony_ci						     se_tpg);
39798c2ecf20Sopenharmony_ci	struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport);
39808c2ecf20Sopenharmony_ci	unsigned long tmp;
39818c2ecf20Sopenharmony_ci	int rc;
39828c2ecf20Sopenharmony_ci	long lrc;
39838c2ecf20Sopenharmony_ci
39848c2ecf20Sopenharmony_ci	rc = kstrtoul(page, 0, &tmp);
39858c2ecf20Sopenharmony_ci	if (rc < 0) {
39868c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Unable to extract srpt_tpg_store_enable\n");
39878c2ecf20Sopenharmony_ci		return -EINVAL;
39888c2ecf20Sopenharmony_ci	}
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	if ((tmp != 0) && (tmp != 1)) {
39918c2ecf20Sopenharmony_ci		dev_err(&vscsi->dev, "Illegal value for srpt_tpg_store_enable\n");
39928c2ecf20Sopenharmony_ci		return -EINVAL;
39938c2ecf20Sopenharmony_ci	}
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_ci	if (tmp) {
39968c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
39978c2ecf20Sopenharmony_ci		tport->enabled = true;
39988c2ecf20Sopenharmony_ci		lrc = ibmvscsis_enable_change_state(vscsi);
39998c2ecf20Sopenharmony_ci		if (lrc)
40008c2ecf20Sopenharmony_ci			dev_err(&vscsi->dev, "enable_change_state failed, rc %ld state %d\n",
40018c2ecf20Sopenharmony_ci				lrc, vscsi->state);
40028c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
40038c2ecf20Sopenharmony_ci	} else {
40048c2ecf20Sopenharmony_ci		spin_lock_bh(&vscsi->intr_lock);
40058c2ecf20Sopenharmony_ci		tport->enabled = false;
40068c2ecf20Sopenharmony_ci		/* This simulates the server going down */
40078c2ecf20Sopenharmony_ci		ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
40088c2ecf20Sopenharmony_ci		spin_unlock_bh(&vscsi->intr_lock);
40098c2ecf20Sopenharmony_ci	}
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci	dev_dbg(&vscsi->dev, "tpg_enable_store, tmp %ld, state %d\n", tmp,
40128c2ecf20Sopenharmony_ci		vscsi->state);
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci	return count;
40158c2ecf20Sopenharmony_ci}
40168c2ecf20Sopenharmony_ciCONFIGFS_ATTR(ibmvscsis_tpg_, enable);
40178c2ecf20Sopenharmony_ci
40188c2ecf20Sopenharmony_cistatic struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
40198c2ecf20Sopenharmony_ci	&ibmvscsis_tpg_attr_enable,
40208c2ecf20Sopenharmony_ci	NULL,
40218c2ecf20Sopenharmony_ci};
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_cistatic const struct target_core_fabric_ops ibmvscsis_ops = {
40248c2ecf20Sopenharmony_ci	.module				= THIS_MODULE,
40258c2ecf20Sopenharmony_ci	.fabric_name			= "ibmvscsis",
40268c2ecf20Sopenharmony_ci	.max_data_sg_nents		= MAX_TXU / PAGE_SIZE,
40278c2ecf20Sopenharmony_ci	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
40288c2ecf20Sopenharmony_ci	.tpg_get_tag			= ibmvscsis_get_tag,
40298c2ecf20Sopenharmony_ci	.tpg_get_default_depth		= ibmvscsis_get_default_depth,
40308c2ecf20Sopenharmony_ci	.tpg_check_demo_mode		= ibmvscsis_check_true,
40318c2ecf20Sopenharmony_ci	.tpg_check_demo_mode_cache	= ibmvscsis_check_true,
40328c2ecf20Sopenharmony_ci	.tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
40338c2ecf20Sopenharmony_ci	.tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
40348c2ecf20Sopenharmony_ci	.tpg_get_inst_index		= ibmvscsis_tpg_get_inst_index,
40358c2ecf20Sopenharmony_ci	.check_stop_free		= ibmvscsis_check_stop_free,
40368c2ecf20Sopenharmony_ci	.release_cmd			= ibmvscsis_release_cmd,
40378c2ecf20Sopenharmony_ci	.sess_get_index			= ibmvscsis_sess_get_index,
40388c2ecf20Sopenharmony_ci	.write_pending			= ibmvscsis_write_pending,
40398c2ecf20Sopenharmony_ci	.set_default_node_attributes	= ibmvscsis_set_default_node_attrs,
40408c2ecf20Sopenharmony_ci	.get_cmd_state			= ibmvscsis_get_cmd_state,
40418c2ecf20Sopenharmony_ci	.queue_data_in			= ibmvscsis_queue_data_in,
40428c2ecf20Sopenharmony_ci	.queue_status			= ibmvscsis_queue_status,
40438c2ecf20Sopenharmony_ci	.queue_tm_rsp			= ibmvscsis_queue_tm_rsp,
40448c2ecf20Sopenharmony_ci	.aborted_task			= ibmvscsis_aborted_task,
40458c2ecf20Sopenharmony_ci	/*
40468c2ecf20Sopenharmony_ci	 * Setup function pointers for logic in target_core_fabric_configfs.c
40478c2ecf20Sopenharmony_ci	 */
40488c2ecf20Sopenharmony_ci	.fabric_make_wwn		= ibmvscsis_make_tport,
40498c2ecf20Sopenharmony_ci	.fabric_drop_wwn		= ibmvscsis_drop_tport,
40508c2ecf20Sopenharmony_ci	.fabric_make_tpg		= ibmvscsis_make_tpg,
40518c2ecf20Sopenharmony_ci	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ci	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
40548c2ecf20Sopenharmony_ci	.tfc_tpg_base_attrs		= ibmvscsis_tpg_attrs,
40558c2ecf20Sopenharmony_ci};
40568c2ecf20Sopenharmony_ci
40578c2ecf20Sopenharmony_cistatic void ibmvscsis_dev_release(struct device *dev) {};
40588c2ecf20Sopenharmony_ci
40598c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_system_id =
40608c2ecf20Sopenharmony_ci	__ATTR(system_id, S_IRUGO, system_id_show, NULL);
40618c2ecf20Sopenharmony_ci
40628c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_partition_number =
40638c2ecf20Sopenharmony_ci	__ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
40648c2ecf20Sopenharmony_ci
40658c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_unit_address =
40668c2ecf20Sopenharmony_ci	__ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
40678c2ecf20Sopenharmony_ci
40688c2ecf20Sopenharmony_cistatic struct attribute *ibmvscsis_dev_attrs[] = {
40698c2ecf20Sopenharmony_ci	&dev_attr_system_id.attr,
40708c2ecf20Sopenharmony_ci	&dev_attr_partition_number.attr,
40718c2ecf20Sopenharmony_ci	&dev_attr_unit_address.attr,
40728c2ecf20Sopenharmony_ci};
40738c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(ibmvscsis_dev);
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_cistatic struct class ibmvscsis_class = {
40768c2ecf20Sopenharmony_ci	.name		= "ibmvscsis",
40778c2ecf20Sopenharmony_ci	.dev_release	= ibmvscsis_dev_release,
40788c2ecf20Sopenharmony_ci	.dev_groups	= ibmvscsis_dev_groups,
40798c2ecf20Sopenharmony_ci};
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_cistatic const struct vio_device_id ibmvscsis_device_table[] = {
40828c2ecf20Sopenharmony_ci	{ "v-scsi-host", "IBM,v-scsi-host" },
40838c2ecf20Sopenharmony_ci	{ "", "" }
40848c2ecf20Sopenharmony_ci};
40858c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
40868c2ecf20Sopenharmony_ci
40878c2ecf20Sopenharmony_cistatic struct vio_driver ibmvscsis_driver = {
40888c2ecf20Sopenharmony_ci	.name = "ibmvscsis",
40898c2ecf20Sopenharmony_ci	.id_table = ibmvscsis_device_table,
40908c2ecf20Sopenharmony_ci	.probe = ibmvscsis_probe,
40918c2ecf20Sopenharmony_ci	.remove = ibmvscsis_remove,
40928c2ecf20Sopenharmony_ci};
40938c2ecf20Sopenharmony_ci
40948c2ecf20Sopenharmony_ci/*
40958c2ecf20Sopenharmony_ci * ibmvscsis_init() - Kernel Module initialization
40968c2ecf20Sopenharmony_ci *
40978c2ecf20Sopenharmony_ci * Note: vio_register_driver() registers callback functions, and at least one
40988c2ecf20Sopenharmony_ci * of those callback functions calls TCM - Linux IO Target Subsystem, thus
40998c2ecf20Sopenharmony_ci * the SCSI Target template must be registered before vio_register_driver()
41008c2ecf20Sopenharmony_ci * is called.
41018c2ecf20Sopenharmony_ci */
41028c2ecf20Sopenharmony_cistatic int __init ibmvscsis_init(void)
41038c2ecf20Sopenharmony_ci{
41048c2ecf20Sopenharmony_ci	int rc = 0;
41058c2ecf20Sopenharmony_ci
41068c2ecf20Sopenharmony_ci	rc = ibmvscsis_get_system_info();
41078c2ecf20Sopenharmony_ci	if (rc) {
41088c2ecf20Sopenharmony_ci		pr_err("rc %d from get_system_info\n", rc);
41098c2ecf20Sopenharmony_ci		goto out;
41108c2ecf20Sopenharmony_ci	}
41118c2ecf20Sopenharmony_ci
41128c2ecf20Sopenharmony_ci	rc = class_register(&ibmvscsis_class);
41138c2ecf20Sopenharmony_ci	if (rc) {
41148c2ecf20Sopenharmony_ci		pr_err("failed class register\n");
41158c2ecf20Sopenharmony_ci		goto out;
41168c2ecf20Sopenharmony_ci	}
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci	rc = target_register_template(&ibmvscsis_ops);
41198c2ecf20Sopenharmony_ci	if (rc) {
41208c2ecf20Sopenharmony_ci		pr_err("rc %d from target_register_template\n", rc);
41218c2ecf20Sopenharmony_ci		goto unregister_class;
41228c2ecf20Sopenharmony_ci	}
41238c2ecf20Sopenharmony_ci
41248c2ecf20Sopenharmony_ci	rc = vio_register_driver(&ibmvscsis_driver);
41258c2ecf20Sopenharmony_ci	if (rc) {
41268c2ecf20Sopenharmony_ci		pr_err("rc %d from vio_register_driver\n", rc);
41278c2ecf20Sopenharmony_ci		goto unregister_target;
41288c2ecf20Sopenharmony_ci	}
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci	return 0;
41318c2ecf20Sopenharmony_ci
41328c2ecf20Sopenharmony_ciunregister_target:
41338c2ecf20Sopenharmony_ci	target_unregister_template(&ibmvscsis_ops);
41348c2ecf20Sopenharmony_ciunregister_class:
41358c2ecf20Sopenharmony_ci	class_unregister(&ibmvscsis_class);
41368c2ecf20Sopenharmony_ciout:
41378c2ecf20Sopenharmony_ci	return rc;
41388c2ecf20Sopenharmony_ci}
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_cistatic void __exit ibmvscsis_exit(void)
41418c2ecf20Sopenharmony_ci{
41428c2ecf20Sopenharmony_ci	pr_info("Unregister IBM virtual SCSI host driver\n");
41438c2ecf20Sopenharmony_ci	vio_unregister_driver(&ibmvscsis_driver);
41448c2ecf20Sopenharmony_ci	target_unregister_template(&ibmvscsis_ops);
41458c2ecf20Sopenharmony_ci	class_unregister(&ibmvscsis_class);
41468c2ecf20Sopenharmony_ci}
41478c2ecf20Sopenharmony_ci
41488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IBMVSCSIS fabric driver");
41498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bryant G. Ly and Michael Cyr");
41508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
41518c2ecf20Sopenharmony_ciMODULE_VERSION(IBMVSCSIS_VERSION);
41528c2ecf20Sopenharmony_cimodule_init(ibmvscsis_init);
41538c2ecf20Sopenharmony_cimodule_exit(ibmvscsis_exit);
4154