ibmvfc.c revision 64b840dd88eb2054f86c72ed6d989cb8681f0058
1c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/* 2c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter 3c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 4c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation 5c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 6c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Copyright (C) IBM Corporation, 2008 7c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 8c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * This program is free software; you can redistribute it and/or modify 9c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * it under the terms of the GNU General Public License as published by 10c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * the Free Software Foundation; either version 2 of the License, or 11c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * (at your option) any later version. 12c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 13c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * This program is distributed in the hope that it will be useful, 14c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * GNU General Public License for more details. 17c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 18c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * You should have received a copy of the GNU General Public License 19c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * along with this program; if not, write to the Free Software 20c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 22c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom */ 23c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 24c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/module.h> 25c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/moduleparam.h> 26c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/dma-mapping.h> 27c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/dmapool.h> 28c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/delay.h> 29c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/interrupt.h> 30c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/kthread.h> 31c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/of.h> 32c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <linux/stringify.h> 33c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <asm/firmware.h> 34c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <asm/irq.h> 35c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <asm/vio.h> 36c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi.h> 37c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi_cmnd.h> 38c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi_host.h> 39c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi_device.h> 40c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi_tcq.h> 41c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include <scsi/scsi_transport_fc.h> 42c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#include "ibmvfc.h" 43c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 44c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int init_timeout = IBMVFC_INIT_TIMEOUT; 45c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; 46c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int max_lun = IBMVFC_MAX_LUN; 47c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int max_targets = IBMVFC_MAX_TARGETS; 48c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; 49c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; 50c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int dev_loss_tmo = IBMVFC_DEV_LOSS_TMO; 51c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int ibmvfc_debug = IBMVFC_DEBUG; 52c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; 53c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic LIST_HEAD(ibmvfc_head); 54c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic DEFINE_SPINLOCK(ibmvfc_driver_lock); 55c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic struct scsi_transport_template *ibmvfc_transport_template; 56c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 57c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_DESCRIPTION("IBM Virtual Fibre Channel Driver"); 58c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_AUTHOR("Brian King <brking@linux.vnet.ibm.com>"); 59c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_LICENSE("GPL"); 60c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_VERSION(IBMVFC_DRIVER_VERSION); 61c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 62c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(init_timeout, init_timeout, uint, S_IRUGO | S_IWUSR); 63c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds. " 64c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_INIT_TIMEOUT) "]"); 65c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(default_timeout, default_timeout, uint, S_IRUGO | S_IWUSR); 66c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(default_timeout, 67c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "Default timeout in seconds for initialization and EH commands. " 68c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_DEFAULT_TIMEOUT) "]"); 69c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(max_requests, max_requests, uint, S_IRUGO); 70c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. " 71c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]"); 72c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(max_lun, max_lun, uint, S_IRUGO); 73c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " 74c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_MAX_LUN) "]"); 75c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(max_targets, max_targets, uint, S_IRUGO); 76c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(max_targets, "Maximum allowed targets. " 77c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]"); 78c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(disc_threads, disc_threads, uint, S_IRUGO | S_IWUSR); 79c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " 80c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]"); 81c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); 82c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(debug, "Enable driver debug information. " 83c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_DEBUG) "]"); 84c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(dev_loss_tmo, dev_loss_tmo, uint, S_IRUGO | S_IWUSR); 85c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC " 86c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "transport should insulate the loss of a remote port. Once this " 87c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "value is exceeded, the scsi target is removed. " 88c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_DEV_LOSS_TMO) "]"); 89c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedommodule_param_named(log_level, log_level, uint, 0); 90c6e0d91464da214081af546496dd3a4b6d19db70Casey LeedomMODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. " 91c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]"); 92c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 93c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const struct { 94c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u16 status; 95c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u16 error; 96c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u8 result; 97c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u8 retry; 98c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int log; 99c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom char *name; 100c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} cmd_status [] = { 101c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, 102c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, 103c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, 104c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" }, 105c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, 106c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, 107c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, 108c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_REGISTER, DID_ERROR, 1, 1, "unable to register" }, 109c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_BUSY, DID_BUS_BUSY, 1, 0, "transport busy" }, 110c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" }, 111c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" }, 112c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, 113c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" }, 114c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" }, 115c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 116c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, 117c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, 118c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" }, 119c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" }, 120c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, 121c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" }, 122c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" }, 123c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, 124c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, 125c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, 126c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 127c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, 128c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_INVALID_VERSION, DID_ERROR, 0, 1, "invalid version level" }, 129c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_ERROR, DID_ERROR, 1, 1, "logical error" }, 130c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_INVALID_CT_IU_SIZE, DID_ERROR, 0, 1, "invalid CT_IU size" }, 131c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_BUSY, DID_REQUEUE, 1, 0, "logical busy" }, 132c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_PROTOCOL_ERROR, DID_ERROR, 1, 1, "protocol error" }, 133c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_UNABLE_TO_PERFORM_REQ, DID_ERROR, 1, 1, "unable to perform request" }, 134c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_CMD_NOT_SUPPORTED, DID_ERROR, 0, 0, "command not supported" }, 135c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_SERVER_NOT_AVAIL, DID_ERROR, 0, 1, "server not available" }, 136c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_CMD_IN_PROGRESS, DID_ERROR, 0, 1, "command already in progress" }, 137c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" }, 138c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 139c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" }, 140c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 141c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 142c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_npiv_login(struct ibmvfc_host *); 143c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_tgt_send_prli(struct ibmvfc_target *); 144c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); 145c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_tgt_query_target(struct ibmvfc_target *); 146c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 147c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *unknown_error = "unknown error"; 148c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 149c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#ifdef CONFIG_SCSI_IBMVFC_TRACE 150c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 151c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_trc_start - Log a start trace entry 152c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 153c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 154c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 155c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_trc_start(struct ibmvfc_event *evt) 156c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 157c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = evt->vhost; 158c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; 159c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_mad_common *mad = &evt->iu.mad_common; 160c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_trace_entry *entry; 161c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 162c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry = &vhost->trace[vhost->trace_index++]; 163c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->evt = evt; 164c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->time = jiffies; 165c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->fmt = evt->crq.format; 166c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->type = IBMVFC_TRC_START; 167c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 168c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (entry->fmt) { 169c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CMD_FORMAT: 170c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->op_code = vfc_cmd->iu.cdb[0]; 171c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->scsi_id = vfc_cmd->tgt_scsi_id; 172c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); 173c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->tmf_flags = vfc_cmd->iu.tmf_flags; 174c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.start.xfer_len = vfc_cmd->iu.xfer_len; 175c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 176c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_MAD_FORMAT: 177c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->op_code = mad->opcode; 178c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 179c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 180c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 181c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 182c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 183c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 184c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 185c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_trc_end - Log an end trace entry 186c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 187c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 188c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 189c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_trc_end(struct ibmvfc_event *evt) 190c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 191c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = evt->vhost; 192c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; 193c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common; 194c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_trace_entry *entry = &vhost->trace[vhost->trace_index++]; 195c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 196c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->evt = evt; 197c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->time = jiffies; 198c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->fmt = evt->crq.format; 199c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->type = IBMVFC_TRC_END; 200c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 201c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (entry->fmt) { 202c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CMD_FORMAT: 203c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->op_code = vfc_cmd->iu.cdb[0]; 204c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->scsi_id = vfc_cmd->tgt_scsi_id; 205c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); 206c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->tmf_flags = vfc_cmd->iu.tmf_flags; 207c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.status = vfc_cmd->status; 208c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.error = vfc_cmd->error; 209c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.fcp_rsp_flags = vfc_cmd->rsp.flags; 210c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.rsp_code = vfc_cmd->rsp.data.info.rsp_code; 211c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.scsi_status = vfc_cmd->rsp.scsi_status; 212c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 213c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_MAD_FORMAT: 214c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->op_code = mad->opcode; 215c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom entry->u.end.status = mad->status; 216c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 217c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 218c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 219c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 220c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 221c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 222c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 223c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#else 224c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#define ibmvfc_trc_start(evt) do { } while (0) 225c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#define ibmvfc_trc_end(evt) do { } while (0) 226c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom#endif 227c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 228c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 229c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_err_index - Find the index into cmd_status for the fcp response 230c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: status / error class 23157b2eaf7ddeae307fac202d82a6fabf5976e575bFUJITA Tomonori * @error: error 23257b2eaf7ddeae307fac202d82a6fabf5976e575bFUJITA Tomonori * 23357b2eaf7ddeae307fac202d82a6fabf5976e575bFUJITA Tomonori * Return value: 23457b2eaf7ddeae307fac202d82a6fabf5976e575bFUJITA Tomonori * index into cmd_status / -EINVAL on failure 23557b2eaf7ddeae307fac202d82a6fabf5976e575bFUJITA Tomonori **/ 236c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_get_err_index(u16 status, u16 error) 237c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 238c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 239c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 240c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < ARRAY_SIZE(cmd_status); i++) 241c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((cmd_status[i].status & status) == cmd_status[i].status && 242c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmd_status[i].error == error) 243c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return i; 244c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 245c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -EINVAL; 246c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 247c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 248c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 249c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_cmd_error - Find the error description for the fcp response 250c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: status / error class 251c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @error: error 252c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 253c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 254c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * error description string 255c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 256c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *ibmvfc_get_cmd_error(u16 status, u16 error) 257c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 258c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = ibmvfc_get_err_index(status, error); 259c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc >= 0) 260c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return cmd_status[rc].name; 261c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return unknown_error; 262c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 263c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 264c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 265c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_err_result - Find the scsi status to return for the fcp response 266c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vfc_cmd: ibmvfc command struct 267c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 268c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 269c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * SCSI result value to return for completed command 270c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 271c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) 272c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 273c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int err; 274c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; 275c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int fc_rsp_len = rsp->fcp_rsp_len; 276c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 277c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rsp->flags & FCP_RSP_LEN_VALID) && 278c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || 279c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp->data.info.rsp_code)) 280c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return DID_ERROR << 16; 281c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 282c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); 283c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (err >= 0) 284c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rsp->scsi_status | (cmd_status[err].result << 16); 285c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rsp->scsi_status | (DID_ERROR << 16); 286c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 287c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 288c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 289c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_retry_cmd - Determine if error status is retryable 290c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: status / error class 291c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @error: error 292c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 293c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 294c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1 if error should be retried / 0 if it should not 295c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 296c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_retry_cmd(u16 status, u16 error) 297c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 298c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = ibmvfc_get_err_index(status, error); 299c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 300c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc >= 0) 301c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return cmd_status[rc].retry; 302c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 1; 303c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 304c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 305c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *unknown_fc_explain = "unknown fc explain"; 306c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 307c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const struct { 308c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u16 fc_explain; 309c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom char *name; 310c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} ls_explain [] = { 311c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x00, "no additional explanation" }, 312c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x01, "service parameter error - options" }, 313c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x03, "service parameter error - initiator control" }, 314c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x05, "service parameter error - recipient control" }, 315c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x07, "service parameter error - received data field size" }, 316c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x09, "service parameter error - concurrent seq" }, 317c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x0B, "service parameter error - credit" }, 318c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x0D, "invalid N_Port/F_Port_Name" }, 319c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x0E, "invalid node/Fabric Name" }, 320c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x0F, "invalid common service parameters" }, 321c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x11, "invalid association header" }, 322c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x13, "association header required" }, 323c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x15, "invalid originator S_ID" }, 324c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x17, "invalid OX_ID-RX-ID combination" }, 325c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x19, "command (request) already in progress" }, 326c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x1E, "N_Port Login requested" }, 327c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x1F, "Invalid N_Port_ID" }, 328c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 329c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 330c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const struct { 331c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u16 fc_explain; 332c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom char *name; 333c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} gs_explain [] = { 334c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x00, "no additional explanation" }, 335c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x01, "port identifier not registered" }, 336c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x02, "port name not registered" }, 337c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x03, "node name not registered" }, 338c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x04, "class of service not registered" }, 339c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x06, "initial process associator not registered" }, 340c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x07, "FC-4 TYPEs not registered" }, 341c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x08, "symbolic port name not registered" }, 342c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x09, "symbolic node name not registered" }, 343c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0x0A, "port type not registered" }, 344c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF0, "authorization exception" }, 345c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF1, "authentication exception" }, 346c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF2, "data base full" }, 347c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF3, "data base empty" }, 348c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF4, "processing request" }, 349c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF5, "unable to verify connection" }, 350c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { 0xF6, "devices not in a common zone" }, 351c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 352c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 353c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 354c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_ls_explain - Return the FC Explain description text 355c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: FC Explain status 356c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 357c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 358c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * error string 359c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 360c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *ibmvfc_get_ls_explain(u16 status) 361c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 362c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 363c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 364c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < ARRAY_SIZE(ls_explain); i++) 365c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (ls_explain[i].fc_explain == status) 366c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ls_explain[i].name; 367c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 368c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return unknown_fc_explain; 369c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 370c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 371c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 372c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_gs_explain - Return the FC Explain description text 373c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: FC Explain status 374c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 375c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 376c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * error string 377c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 378c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *ibmvfc_get_gs_explain(u16 status) 379c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 380c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 381c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 382c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < ARRAY_SIZE(gs_explain); i++) 383c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (gs_explain[i].fc_explain == status) 384c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return gs_explain[i].name; 385c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 386c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return unknown_fc_explain; 387c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 388c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 389c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const struct { 390c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_fc_type fc_type; 391c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom char *name; 392c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} fc_type [] = { 393c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_REJECT, "fabric reject" }, 394c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_PORT_REJECT, "port reject" }, 395c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_LS_REJECT, "ELS reject" }, 396c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_FABRIC_BUSY, "fabric busy" }, 397c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_PORT_BUSY, "port busy" }, 398c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_BASIC_REJECT, "basic reject" }, 399c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 400c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 401c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *unknown_fc_type = "unknown fc type"; 402c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 403c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 404c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_fc_type - Return the FC Type description text 405c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @status: FC Type error status 406c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 407c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 408c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * error string 409c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 410c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *ibmvfc_get_fc_type(u16 status) 411c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 412c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 413c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 414c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < ARRAY_SIZE(fc_type); i++) 415c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (fc_type[i].fc_type == status) 416c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return fc_type[i].name; 417c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 418c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return unknown_fc_type; 419c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 420c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 421c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 422c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_set_tgt_action - Set the next init action for the target 423c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @tgt: ibmvfc target struct 424c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @action: action to perform 425c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 426c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 427c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, 428c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_target_action action) 429c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 430c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (tgt->action) { 431c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_TGT_ACTION_DEL_RPORT: 432c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 433c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 434c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tgt->action = action; 435c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 436c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 437c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 438c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 439c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 440c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_set_host_state - Set the state for the host 441c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 442c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @state: state to set host to 443c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 444c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 445c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 if state changed / non-zero if not changed 446c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 447c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_set_host_state(struct ibmvfc_host *vhost, 448c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_host_state state) 449c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 450c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = 0; 451c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 452c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (vhost->state) { 453c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_OFFLINE: 454c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = -EINVAL; 455c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 456c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 457c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state = state; 458c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 459c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 460c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 461c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 462c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 463c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 464c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 465c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_set_host_action - Set the next init action for the host 466c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 467c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @action: action to perform 468c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 469c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 470c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_set_host_action(struct ibmvfc_host *vhost, 471c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_host_action action) 472c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 473c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (action) { 474c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_ALLOC_TGTS: 475c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) 476c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action = action; 477c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 478c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_INIT_WAIT: 479c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_INIT) 480c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action = action; 481c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 482c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_QUERY: 483c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (vhost->action) { 484c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_INIT_WAIT: 485c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_NONE: 486c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_TGT_ADD: 487c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action = action; 488c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 489c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 490c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 491c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 492c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 493c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_TGT_INIT: 494c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) 495c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action = action; 496c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 497c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_INIT: 498c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_TGT_DEL: 499c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_QUERY_TGTS: 500c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 501c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_TGT_ADD: 502c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_ACTION_NONE: 503c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 504c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action = action; 505c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 506c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 507c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 508c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 509c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 510c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_reinit_host - Re-start host initialization (no NPIV Login) 511c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 512c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 513c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 514c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * nothing 515c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 516c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_reinit_host(struct ibmvfc_host *vhost) 517c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 518c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_NONE) { 519c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { 520c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_block_requests(vhost->host); 521c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); 522c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 523c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 524c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->reinit = 1; 525c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 526c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wake_up(&vhost->work_wait_q); 527c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 528c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 529c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 530c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_link_down - Handle a link down event from the adapter 531c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 532c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @state: ibmvfc host state to enter 533c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 534c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 535c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_link_down(struct ibmvfc_host *vhost, 536c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_host_state state) 537c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 538c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt; 539c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 540c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 541c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_block_requests(vhost->host); 542c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(tgt, &vhost->targets, queue) 543c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 544c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_state(vhost, state); 545c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); 546c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->events_to_log |= IBMVFC_AE_LINKDOWN; 547c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wake_up(&vhost->work_wait_q); 548c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 549c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 550c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 551c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 552c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_init_host - Start host initialization 553c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 554c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @relogin: is this a re-login? 555c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 556c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 557c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * nothing 558c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 559c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin) 560c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 561c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt; 562c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 563c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { 564c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { 565c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, 566c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "Host initialization retries exceeded. Taking adapter offline\n"); 567c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); 568c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 569c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 570c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 571c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 572c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { 573c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!relogin) { 574c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(vhost->async_crq.msgs, 0, PAGE_SIZE); 575c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->async_crq.cur = 0; 576c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 577c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 578c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(tgt, &vhost->targets, queue) 579c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tgt->need_login = 1; 580c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_block_requests(vhost->host); 581c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); 582c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->job_step = ibmvfc_npiv_login; 583c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wake_up(&vhost->work_wait_q); 584c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 585c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 586c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 587c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 588c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_send_crq - Send a CRQ 589c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 590c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @word1: the first 64 bits of the data 591c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @word2: the second 64 bits of the data 592c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 593c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 594c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 595c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 596c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_send_crq(struct ibmvfc_host *vhost, u64 word1, u64 word2) 597c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 598c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct vio_dev *vdev = to_vio_dev(vhost->dev); 599c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); 600c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 601c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 602c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 603c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_send_crq_init - Send a CRQ init message 604c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 605c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 606c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 607c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 608c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 609c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_send_crq_init(struct ibmvfc_host *vhost) 610c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 611c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_dbg(vhost, "Sending CRQ init\n"); 612c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ibmvfc_send_crq(vhost, 0xC001000000000000LL, 0); 613c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 614c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 615c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 616c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_send_crq_init_complete - Send a CRQ init complete message 617c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 618c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 619c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 620c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 621c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 622c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) 623c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 624c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_dbg(vhost, "Sending CRQ init complete\n"); 625c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ibmvfc_send_crq(vhost, 0xC002000000000000LL, 0); 626c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 627c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 628c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 629c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_release_crq_queue - Deallocates data and unregisters CRQ 630c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 631c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 632c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Frees irq, deallocates a page for messages, unmaps dma, and unregisters 633c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * the crq with the hypervisor. 634c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 635c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) 636c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 637c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom long rc; 638c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct vio_dev *vdev = to_vio_dev(vhost->dev); 639c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_crq_queue *crq = &vhost->crq; 640c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 641c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_dbg(vhost, "Releasing CRQ\n"); 642c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom free_irq(vdev->irq, vhost); 643c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom do { 644c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 645c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 646c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 647c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state = IBMVFC_NO_CRQ; 648c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); 649c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom free_page((unsigned long)crq->msgs); 650c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 651c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 652c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 653c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_reenable_crq_queue - reenables the CRQ 654c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 655c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 656c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 657c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 658c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 659c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) 660c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 661c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 662c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct vio_dev *vdev = to_vio_dev(vhost->dev); 663c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 664c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Re-enable the CRQ */ 665c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom do { 666c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); 667c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); 668c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 669c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc) 670c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc); 671c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 672c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 673c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 674c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 675c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 676c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_reset_crq - resets a crq after a failure 677c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 678c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 679c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 680c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 681c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 682c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_reset_crq(struct ibmvfc_host *vhost) 683c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 684c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 685c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct vio_dev *vdev = to_vio_dev(vhost->dev); 686c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_crq_queue *crq = &vhost->crq; 687c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 688c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Close the CRQ */ 689c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom do { 690c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 691c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 692c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 693c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state = IBMVFC_NO_CRQ; 694c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 695c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 696c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Clean out the queue */ 697c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(crq->msgs, 0, PAGE_SIZE); 698c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom crq->cur = 0; 699c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 700c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* And re-open it again */ 701c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, 702c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom crq->msg_token, PAGE_SIZE); 703c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 704c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc == H_CLOSED) 705c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Adapter is good, but other end is not ready */ 706c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_warn(vhost->dev, "Partner adapter not ready\n"); 707c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else if (rc != 0) 708c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); 709c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 710c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 711c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 712c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 713c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 714c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_valid_event - Determines if event is valid. 715c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @pool: event_pool that contains the event 716c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event to be checked for validity 717c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 718c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 719c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1 if event is valid / 0 if event is not valid 720c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 721c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_valid_event(struct ibmvfc_event_pool *pool, 722c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt) 723c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 724c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int index = evt - pool->events; 725c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (index < 0 || index >= pool->size) /* outside of bounds */ 726c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 727c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt != pool->events + index) /* unaligned */ 728c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 729c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 1; 730c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 731c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 732c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 733c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_free_event - Free the specified event 734c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc_event to be freed 735c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 736c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 737c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_free_event(struct ibmvfc_event *evt) 738c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 739c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = evt->vhost; 740c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event_pool *pool = &vhost->pool; 741c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 742c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom BUG_ON(!ibmvfc_valid_event(pool, evt)); 743c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom BUG_ON(atomic_inc_return(&evt->free) != 1); 744c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_add_tail(&evt->queue, &vhost->free); 745c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 746c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 747c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 748c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_scsi_eh_done - EH done function for queuecommand commands 749c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 750c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 751c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * This function does not setup any error status, that must be done 752c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * before this function gets called. 753c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 754c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) 755c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 756c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_cmnd *cmnd = evt->cmnd; 757c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 758c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (cmnd) { 759c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_dma_unmap(cmnd); 760c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->scsi_done(cmnd); 761c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 762c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 763c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->eh_comp) 764c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom complete(evt->eh_comp); 765c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 766c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 767c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 768c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 769c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 770c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_fail_request - Fail request with specified error code 771c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 772c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @error_code: error code to fail request with 773c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 774c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 775c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 776c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 777c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code) 778c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 779c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd) { 780c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->cmnd->result = (error_code << 16); 781c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done = ibmvfc_scsi_eh_done; 782c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 783c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->xfer_iu->mad_common.status = IBMVFC_MAD_DRIVER_FAILED; 784c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 785c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_del(&evt->queue); 786c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom del_timer(&evt->timer); 787c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_trc_end(evt); 788c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done(evt); 789c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 790c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 791c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 792c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_purge_requests - Our virtual adapter just shut down. Purge any sent requests 793c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 794c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @error_code: error code to fail requests with 795c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 796c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 797c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 798c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 799c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) 800c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 801c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt, *pos; 802c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 803c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_dbg(vhost, "Purging all requests\n"); 804c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry_safe(evt, pos, &vhost->sent, queue) 805c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_fail_request(evt, error_code); 806c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 807c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 808c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 809c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * __ibmvfc_reset_host - Reset the connection to the server (no locking) 810c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: struct ibmvfc host to reset 811c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 812c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void __ibmvfc_reset_host(struct ibmvfc_host *vhost) 813c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 814c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 815c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 816c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_block_requests(vhost->host); 817c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_purge_requests(vhost, DID_ERROR); 818c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rc = ibmvfc_reset_crq(vhost)) || 819c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (rc = ibmvfc_send_crq_init(vhost)) || 820c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { 821c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Error after reset rc=%d\n", rc); 822c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 823c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 824c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); 825c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 826c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 827c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 828c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_reset_host - Reset the connection to the server 829c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: struct ibmvfc host to reset 830c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 831c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_reset_host(struct ibmvfc_host *vhost) 832c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 833c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 834c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 835c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 836c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom __ibmvfc_reset_host(vhost); 837c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 838c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 839c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 840c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 841c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_retry_host_init - Retry host initialization if allowed 842c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 843c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 844c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 845c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) 846c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 847c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { 848c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->delay_init = 1; 849c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { 850c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, 851c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "Host initialization retries exceeded. Taking adapter offline\n"); 852c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); 853c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) 854c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom __ibmvfc_reset_host(vhost); 855c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 856c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); 857c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 858c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 859c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wake_up(&vhost->work_wait_q); 860c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 861c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 862c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 863c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * __ibmvfc_get_target - Find the specified scsi_target (no locking) 864c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: scsi target struct 865c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 866c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 867c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_target struct / NULL if not found 868c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 869c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget) 870c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 871c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 872c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 873c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt; 874c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 875c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(tgt, &vhost->targets, queue) 876c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (tgt->target_id == starget->id) { 877c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kref_get(&tgt->kref); 878c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return tgt; 879c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 880c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return NULL; 881c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 882c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 883c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 884c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_target - Find the specified scsi_target 885c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: scsi target struct 886c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 887c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 888c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_target struct / NULL if not found 889c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 890c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget) 891c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 892c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 893c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt; 894c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 895c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 896c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 897c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tgt = __ibmvfc_get_target(starget); 898c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 899c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return tgt; 900c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 901c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 902c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 903c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_host_speed - Get host port speed 904c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @shost: scsi host struct 905c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 906c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 907c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 908c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 909c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_get_host_speed(struct Scsi_Host *shost) 910c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 911c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 912c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 913c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 914c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 915c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->state == IBMVFC_ACTIVE) { 916c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (vhost->login_buf->resp.link_speed / 100) { 917c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 1: 918c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_1GBIT; 919c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 920c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 2: 921c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_2GBIT; 922c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 923c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 4: 924c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_4GBIT; 925c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 926c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 8: 927c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_8GBIT; 928c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 929c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 10: 930c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_10GBIT; 931c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 932c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case 16: 933c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_16GBIT; 934c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 935c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 936c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_log(vhost, 3, "Unknown port speed: %lld Gbit\n", 937c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->login_buf->resp.link_speed / 100); 938c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; 939c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 940c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 941c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 942c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; 943c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 944c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 945c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 946c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 947c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_host_port_state - Get host port state 948c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @shost: scsi host struct 949c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 950c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 951c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 952c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 953c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_get_host_port_state(struct Scsi_Host *shost) 954c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 955c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 956c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 957c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 958c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 959c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (vhost->state) { 960c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_INITIALIZING: 961c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_ACTIVE: 962c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; 963c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 964c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_LINK_DOWN: 965c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; 966c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 967c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_LINK_DEAD: 968c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_OFFLINE: 969c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; 970c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 971c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HALTED: 972c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; 973c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 974c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_NO_CRQ: 975c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 976c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 977c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 978c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); 979c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 980c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 981c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 982c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 983c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 984c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 985c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 986c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_set_rport_dev_loss_tmo - Set rport's device loss timeout 987c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @rport: rport struct 988c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @timeout: timeout value 989c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 990c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 991c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 992c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 993c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) 994c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 995c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (timeout) 996c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rport->dev_loss_tmo = timeout; 997c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 998c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rport->dev_loss_tmo = 1; 999c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1000c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1001c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1002c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_release_tgt - Free memory allocated for a target 1003c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @kref: kref struct 1004c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1005c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1006c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_release_tgt(struct kref *kref) 1007c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1008c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); 1009c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kfree(tgt); 1010c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1011c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1012c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1013c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_starget_node_name - Get SCSI target's node name 1014c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: scsi target struct 1015c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1016c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1017c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 1018c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1019c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_get_starget_node_name(struct scsi_target *starget) 1020c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1021c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt = ibmvfc_get_target(starget); 1022c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; 1023c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (tgt) 1024c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kref_put(&tgt->kref, ibmvfc_release_tgt); 1025c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1026c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1027c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1028c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_starget_port_name - Get SCSI target's port name 1029c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: scsi target struct 1030c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1031c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1032c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 1033c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1034c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_get_starget_port_name(struct scsi_target *starget) 1035c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1036c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt = ibmvfc_get_target(starget); 1037c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; 1038c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (tgt) 1039c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kref_put(&tgt->kref, ibmvfc_release_tgt); 1040c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1041c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1042c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1043c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_starget_port_id - Get SCSI target's port ID 1044c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: scsi target struct 1045c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1046c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1047c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 1048c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1049c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_get_starget_port_id(struct scsi_target *starget) 1050c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1051c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_target *tgt = ibmvfc_get_target(starget); 1052c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; 1053c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (tgt) 1054c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kref_put(&tgt->kref, ibmvfc_release_tgt); 1055c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1056c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1057c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1058c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_wait_while_resetting - Wait while the host resets 1059c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 1060c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1061c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1062c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1063c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1064c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_wait_while_resetting(struct ibmvfc_host *vhost) 1065c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1066c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom long timeout = wait_event_timeout(vhost->init_wait_q, 1067c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ((vhost->state == IBMVFC_ACTIVE || 1068c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state == IBMVFC_HOST_OFFLINE || 1069c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state == IBMVFC_LINK_DEAD) && 1070c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->action == IBMVFC_HOST_ACTION_NONE), 1071c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (init_timeout * HZ)); 1072c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1073c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return timeout ? 0 : -EIO; 1074c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1075c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1076c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1077c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_issue_fc_host_lip - Re-initiate link initialization 1078c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @shost: scsi host struct 1079c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1080c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1081c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1082c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1083c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_issue_fc_host_lip(struct Scsi_Host *shost) 1084c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1085c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 1086c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1087c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Initiating host LIP. Resetting connection\n"); 1088c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_reset_host(vhost); 1089c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ibmvfc_wait_while_resetting(vhost); 1090c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1091c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1092c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1093c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_gather_partition_info - Gather info about the LPAR 1094c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1095c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1096c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 1097c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1098c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) 1099c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1100c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct device_node *rootdn; 1101c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const char *name; 1102c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const unsigned int *num; 1103c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1104c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rootdn = of_find_node_by_path("/"); 1105c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!rootdn) 1106c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 1107c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1108c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom name = of_get_property(rootdn, "ibm,partition-name", NULL); 1109c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (name) 1110c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); 1111c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom num = of_get_property(rootdn, "ibm,partition-no", NULL); 1112c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (num) 1113c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->partition_number = *num; 1114c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom of_node_put(rootdn); 1115c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1116c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1117c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1118c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_set_login_info - Setup info for NPIV login 1119c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 1120c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1121c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 1122c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 1123c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1124c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_set_login_info(struct ibmvfc_host *vhost) 1125c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1126c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_npiv_login *login_info = &vhost->login_info; 1127c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct device_node *of_node = vhost->dev->archdata.of_node; 1128c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const char *location; 1129c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1130c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(login_info, 0, sizeof(*login_info)); 1131c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1132c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->ostype = IBMVFC_OS_LINUX; 1133c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->max_dma_len = IBMVFC_MAX_SECTORS << 9; 1134c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->max_payload = sizeof(struct ibmvfc_fcp_cmd_iu); 1135c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->max_response = sizeof(struct ibmvfc_fcp_rsp); 1136c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->partition_num = vhost->partition_number; 1137c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->vfc_frame_version = 1; 1138c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->fcp_version = 3; 1139c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->client_migrated) 1140c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->flags = IBMVFC_CLIENT_MIGRATED; 1141c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1142c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; 1143c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->capabilities = IBMVFC_CAN_MIGRATE; 1144c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->async.va = vhost->async_crq.msg_token; 1145c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs); 1146c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); 1147c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom strncpy(login_info->device_name, 1148c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME); 1149c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1150c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom location = of_get_property(of_node, "ibm,loc-code", NULL); 1151c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom location = location ? location : dev_name(vhost->dev); 1152c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); 1153c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1154c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1155c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1156c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host 1157c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host who owns the event pool 1158c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1159c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns zero on success. 1160c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1161c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_init_event_pool(struct ibmvfc_host *vhost) 1162c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1163c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 1164c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event_pool *pool = &vhost->pool; 1165c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1166c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 1167c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->size = max_requests + IBMVFC_NUM_INTERNAL_REQ; 1168c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); 1169c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!pool->events) 1170c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -ENOMEM; 1171c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1172c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->iu_storage = dma_alloc_coherent(vhost->dev, 1173c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->size * sizeof(*pool->iu_storage), 1174c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom &pool->iu_token, 0); 1175c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1176c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!pool->iu_storage) { 1177c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kfree(pool->events); 1178c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -ENOMEM; 1179c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1180c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1181c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < pool->size; ++i) { 1182c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt = &pool->events[i]; 1183c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom atomic_set(&evt->free, 1); 1184c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->crq.valid = 0x80; 1185c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->crq.ioba = pool->iu_token + (sizeof(*evt->xfer_iu) * i); 1186c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->xfer_iu = pool->iu_storage + i; 1187c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->vhost = vhost; 1188c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->ext_list = NULL; 1189c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_add_tail(&evt->queue, &vhost->free); 1190c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1191c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1192c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 1193c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1194c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1195c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1196c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1197c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_free_event_pool - Frees memory of the event pool of a host 1198c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host who owns the event pool 1199c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1200c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1201c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_free_event_pool(struct ibmvfc_host *vhost) 1202c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1203c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 1204c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event_pool *pool = &vhost->pool; 1205c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1206c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 1207c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < pool->size; ++i) { 1208c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_del(&pool->events[i].queue); 1209c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom BUG_ON(atomic_read(&pool->events[i].free) != 1); 1210c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (pool->events[i].ext_list) 1211c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dma_pool_free(vhost->sg_pool, 1212c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->events[i].ext_list, 1213c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->events[i].ext_list_token); 1214c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1215c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1216c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom kfree(pool->events); 1217c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dma_free_coherent(vhost->dev, 1218c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->size * sizeof(*pool->iu_storage), 1219c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom pool->iu_storage, pool->iu_token); 1220c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 1221c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1222c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1223c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1224c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_event - Gets the next free event in pool 1225c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 1226c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1227c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns a free event from the pool. 1228c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1229c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_host *vhost) 1230c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1231c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt; 1232c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1233c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom BUG_ON(list_empty(&vhost->free)); 1234c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt = list_entry(vhost->free.next, struct ibmvfc_event, queue); 1235c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom atomic_set(&evt->free, 0); 1236c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_del(&evt->queue); 1237c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return evt; 1238c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1239c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1240c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1241c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_init_event - Initialize fields in an event struct that are always 1242c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * required. 1243c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: The event 1244c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @done: Routine to call when the event is responded to 1245c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @format: SRP or MAD format 1246c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1247c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_init_event(struct ibmvfc_event *evt, 1248c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom void (*done) (struct ibmvfc_event *), u8 format) 1249c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1250c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->cmnd = NULL; 1251c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->sync_iu = NULL; 1252c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->crq.format = format; 1253c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done = done; 1254c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->eh_comp = NULL; 1255c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1256c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1257c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1258c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_map_sg_list - Initialize scatterlist 1259c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @scmd: scsi command struct 1260c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @nseg: number of scatterlist segments 1261c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @md: memory descriptor list to initialize 1262c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1263c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_map_sg_list(struct scsi_cmnd *scmd, int nseg, 1264c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct srp_direct_buf *md) 1265c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1266c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 1267c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scatterlist *sg; 1268c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1269c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_for_each_sg(scmd, sg, nseg, i) { 1270c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom md[i].va = sg_dma_address(sg); 1271c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom md[i].len = sg_dma_len(sg); 1272c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom md[i].key = 0; 1273c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1274c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1275c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1276c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1277c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes decriptor fields 1278c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @scmd: Scsi_Cmnd with the scatterlist 1279c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 1280c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vfc_cmd: vfc_cmd that contains the memory descriptor 1281c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @dev: device for which to map dma memory 1282c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1283c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1284c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / non-zero on failure 1285c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1286c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, 1287c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt, 1288c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd, struct device *dev) 1289c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1290c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1291c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int sg_mapped; 1292c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct srp_direct_buf *data = &vfc_cmd->ioba; 1293c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = dev_get_drvdata(dev); 1294c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1295c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sg_mapped = scsi_dma_map(scmd); 1296c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!sg_mapped) { 1297c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->flags |= IBMVFC_NO_MEM_DESC; 1298c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1299c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else if (unlikely(sg_mapped < 0)) { 130064bb336c8f4de8b281d0d44f2ec2c900b9b28466Casey Leedom if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) 1301c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scmd_printk(KERN_ERR, scmd, "Failed to map DMA buffer for command\n"); 1302c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return sg_mapped; 1303c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1304c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1305c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (scmd->sc_data_direction == DMA_TO_DEVICE) { 1306c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->flags |= IBMVFC_WRITE; 1307c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.add_cdb_len |= IBMVFC_WRDATA; 1308c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else { 1309c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->flags |= IBMVFC_READ; 1310c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.add_cdb_len |= IBMVFC_RDDATA; 1311c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1312c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1313c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (sg_mapped == 1) { 1314c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_map_sg_list(scmd, sg_mapped, data); 1315c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1316c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1317c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1318c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->flags |= IBMVFC_SCATTERLIST; 1319c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1320c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!evt->ext_list) { 1321c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC, 1322c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom &evt->ext_list_token); 1323c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1324c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!evt->ext_list) { 1325c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_dma_unmap(scmd); 1326c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) 1327c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); 1328c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -ENOMEM; 1329c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1330c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1331c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1332c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_map_sg_list(scmd, sg_mapped, evt->ext_list); 1333c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1334c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom data->va = evt->ext_list_token; 1335c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom data->len = sg_mapped * sizeof(struct srp_direct_buf); 1336c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom data->key = 0; 1337c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1338c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1339c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1340c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1341c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_timeout - Internal command timeout handler 1342c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: struct ibmvfc_event that timed out 1343c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1344c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Called when an internally generated command times out 1345c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1346c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_timeout(struct ibmvfc_event *evt) 1347c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1348c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = evt->vhost; 1349c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); 1350c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_reset_host(vhost); 1351c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1352c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1353c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1354c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_send_event - Transforms event to u64 array and calls send_crq() 1355c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: event to be sent 1356c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 1357c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @timeout: timeout in seconds - 0 means do not time command 1358c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1359c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns the value returned from ibmvfc_send_crq(). (Zero for success) 1360c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1361c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_send_event(struct ibmvfc_event *evt, 1362c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost, unsigned long timeout) 1363c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1364c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u64 *crq_as_u64 = (u64 *) &evt->crq; 1365c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 1366c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1367c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Copy the IU into the transfer area */ 1368c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom *evt->xfer_iu = evt->iu; 1369c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->crq.format == IBMVFC_CMD_FORMAT) 1370c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->xfer_iu->cmd.tag = (u64)evt; 1371c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else if (evt->crq.format == IBMVFC_MAD_FORMAT) 1372c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->xfer_iu->mad_common.tag = (u64)evt; 1373c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 1374c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom BUG(); 1375c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1376c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_add_tail(&evt->queue, &vhost->sent); 1377c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom init_timer(&evt->timer); 1378c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1379c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (timeout) { 1380c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->timer.data = (unsigned long) evt; 1381c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->timer.expires = jiffies + (timeout * HZ); 1382c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->timer.function = (void (*)(unsigned long))ibmvfc_timeout; 1383c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom add_timer(&evt->timer); 1384c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1385c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1386c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom mb(); 1387c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1388c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { 1389c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_del(&evt->queue); 1390c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom del_timer(&evt->timer); 1391c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1392c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. 1393c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Firmware will send a CRQ with a transport event (0xFF) to 1394c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * tell this client what has happened to the transport. This 1395c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * will be handled in ibmvfc_handle_crq() 1396c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom */ 1397c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc == H_CLOSED) { 1398c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (printk_ratelimit()) 1399c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_warn(vhost->dev, "Send warning. Receive queue closed, will retry.\n"); 1400c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd) 1401c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_dma_unmap(evt->cmnd); 1402c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1403c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return SCSI_MLQUEUE_HOST_BUSY; 1404c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1405c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1406c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Send error (rc=%d)\n", rc); 1407c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd) { 1408c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->cmnd->result = DID_ERROR << 16; 1409c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done = ibmvfc_scsi_eh_done; 1410c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 1411c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->xfer_iu->mad_common.status = IBMVFC_MAD_CRQ_ERROR; 1412c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1413c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done(evt); 1414c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 1415c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_trc_start(evt); 1416c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1417c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1418c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1419c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1420c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1421c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_log_error - Log an error for the failed command if appropriate 1422c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event to log 1423c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1424c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1425c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_log_error(struct ibmvfc_event *evt) 1426c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1427c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; 1428c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = evt->vhost; 1429c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; 1430c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_cmnd *cmnd = evt->cmnd; 1431c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const char *err = unknown_error; 1432c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int index = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); 1433c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int logerr = 0; 1434c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_code = 0; 1435c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1436c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (index >= 0) { 1437c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom logerr = cmd_status[index].log; 1438c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom err = cmd_status[index].name; 1439c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1440c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1441c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1))) 1442c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 1443c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1444c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp->flags & FCP_RSP_LEN_VALID) 1445c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_code = rsp->data.info.rsp_code; 1446c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1447c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) " 1448c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n", 1449c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error, 1450c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); 1451c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1452c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1453c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1454c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_scsi_done - Handle responses from commands 1455c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event to be handled 1456c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1457c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Used as a callback when sending scsi cmds. 1458c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1459c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_scsi_done(struct ibmvfc_event *evt) 1460c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1461c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; 1462c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; 1463c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_cmnd *cmnd = evt->cmnd; 1464c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u32 rsp_len = 0; 1465c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u32 sense_len = rsp->fcp_sense_len; 1466c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1467c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (cmnd) { 1468c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vfc_cmd->response_flags & IBMVFC_ADAPTER_RESID_VALID) 1469c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_set_resid(cmnd, vfc_cmd->adapter_resid); 1470c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else if (rsp->flags & FCP_RESID_UNDER) 1471c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_set_resid(cmnd, rsp->fcp_resid); 1472c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 1473c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_set_resid(cmnd, 0); 1474c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1475c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vfc_cmd->status) { 1476c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = ibmvfc_get_err_result(vfc_cmd); 1477c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1478c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp->flags & FCP_RSP_LEN_VALID) 1479c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_len = rsp->fcp_rsp_len; 1480c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((sense_len + rsp_len) > SCSI_SENSE_BUFFERSIZE) 1481c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; 1482c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) 1483c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); 1484c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) 1485c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_reinit_host(evt->vhost); 1486c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1487c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) 1488c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = (DID_ERROR << 16); 1489c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1490c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_log_error(evt); 1491c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1492c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1493c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cmnd->result && 1494c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow)) 1495c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = (DID_ERROR << 16); 1496c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1497c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_dma_unmap(cmnd); 1498c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->scsi_done(cmnd); 1499c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1500c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1501c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->eh_comp) 1502c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom complete(evt->eh_comp); 1503c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1504c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1505c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1506c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1507c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1508c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_host_chkready - Check if the host can accept commands 1509c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: struct ibmvfc host 1510c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1511c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1512c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1 if host can accept command / 0 if not 1513c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1514c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost) 1515c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1516c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int result = 0; 1517c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1518c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (vhost->state) { 1519c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_LINK_DEAD: 1520c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HOST_OFFLINE: 1521c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom result = DID_NO_CONNECT << 16; 1522c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1523c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_NO_CRQ: 1524c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_INITIALIZING: 1525c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_HALTED: 1526c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_LINK_DOWN: 1527c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom result = DID_REQUEUE << 16; 1528c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1529c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_ACTIVE: 1530c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom result = 0; 1531c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1532c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 1533c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1534c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return result; 1535c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1536c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1537c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1538c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_queuecommand - The queuecommand function of the scsi template 1539c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @cmnd: struct scsi_cmnd to be executed 1540c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @done: Callback function to be called when cmnd is completed 1541c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1542c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1543c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1544c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1545c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_queuecommand(struct scsi_cmnd *cmnd, 1546c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom void (*done) (struct scsi_cmnd *)) 1547c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1548c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(cmnd->device->host); 1549c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); 1550c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *vfc_cmd; 1551c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt; 1552c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u8 tag[2]; 1553c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 1554c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1555c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (unlikely((rc = fc_remote_port_chkready(rport))) || 1556c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unlikely((rc = ibmvfc_host_chkready(vhost)))) { 1557c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = rc; 1558c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom done(cmnd); 1559c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1560c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1561c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1562c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = (DID_OK << 16); 1563c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt = ibmvfc_get_event(vhost); 1564c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); 1565c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->cmnd = cmnd; 1566c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->scsi_done = done; 1567c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd = &evt->iu.cmd; 1568c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(vfc_cmd, 0, sizeof(*vfc_cmd)); 1569c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); 1570c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->resp.len = sizeof(vfc_cmd->rsp); 1571c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->frame_type = IBMVFC_SCSI_FCP_TYPE; 1572c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->payload_len = sizeof(vfc_cmd->iu); 1573c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); 1574c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; 1575c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->tgt_scsi_id = rport->port_id; 1576c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rport->supported_classes & FC_COS_CLASS3) && 1577c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3)) 1578c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->flags = IBMVFC_CLASS_3_ERR; 1579c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); 1580c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); 1581c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); 1582c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1583c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (scsi_populate_tag_msg(cmnd, tag)) { 1584c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->task_tag = tag[1]; 1585c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (tag[0]) { 1586c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case MSG_SIMPLE_TAG: 1587c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK; 1588c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1589c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case MSG_HEAD_TAG: 1590c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.pri_task_attr = IBMVFC_HEAD_OF_QUEUE; 1591c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1592c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case MSG_ORDERED_TAG: 1593c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vfc_cmd->iu.pri_task_attr = IBMVFC_ORDERED_TASK; 1594c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1595c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 1596c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1597c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1598c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev)))) 1599c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ibmvfc_send_event(evt, vhost, 0); 1600c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1601c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1602c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc == -ENOMEM) 1603c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return SCSI_MLQUEUE_HOST_BUSY; 1604c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1605c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) 1606c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scmd_printk(KERN_ERR, cmnd, 1607c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "Failed to map DMA buffer for command. rc=%d\n", rc); 1608c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1609c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cmnd->result = DID_ERROR << 16; 1610c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom done(cmnd); 1611c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1612c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1613c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1614c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1615c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_sync_completion - Signal that a synchronous command has completed 1616c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 1617c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1618c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1619c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_sync_completion(struct ibmvfc_event *evt) 1620c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1621c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* copy the response back */ 1622c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->sync_iu) 1623c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom *evt->sync_iu = *evt->xfer_iu; 1624c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1625c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom complete(&evt->comp); 1626c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1627c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1628c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1629c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_reset_device - Reset the device with the specified reset type 1630c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device to reset 1631c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @type: reset type 1632c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @desc: reset type description for log messages 1633c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1634c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1635c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1636c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1637c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) 1638c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1639c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 1640c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 1641c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *tmf; 1642c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt = NULL; 1643c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom union ibmvfc_iu rsp_iu; 1644c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; 1645c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_rc = -EBUSY; 1646c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 1647c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_code = 0; 1648c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1649c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1650c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->state == IBMVFC_ACTIVE) { 1651c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt = ibmvfc_get_event(vhost); 1652c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); 1653c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1654c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf = &evt->iu.cmd; 1655c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(tmf, 0, sizeof(*tmf)); 1656c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); 1657c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp.len = sizeof(tmf->rsp); 1658c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; 1659c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->payload_len = sizeof(tmf->iu); 1660c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp_len = sizeof(tmf->rsp); 1661c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->cancel_key = (unsigned long)sdev->hostdata; 1662c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->tgt_scsi_id = rport->port_id; 1663c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int_to_scsilun(sdev->lun, &tmf->iu.lun); 1664c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); 1665c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->iu.tmf_flags = type; 1666c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->sync_iu = &rsp_iu; 1667c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1668c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom init_completion(&evt->comp); 1669c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); 1670c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1671c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1672c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1673c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp_rc != 0) { 1674c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_ERR, sdev, "Failed to send %s reset event. rc=%d\n", 1675c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom desc, rsp_rc); 1676c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -EIO; 1677c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1678c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1679c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc); 1680c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait_for_completion(&evt->comp); 1681c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1682c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp_iu.cmd.status) { 1683c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (fc_rsp->flags & FCP_RSP_LEN_VALID) 1684c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_code = fc_rsp->data.info.rsp_code; 1685c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1686c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) " 1687c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "flags: %x fcp_rsp: %x, scsi_status: %x\n", 1688c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom desc, ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), 1689c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, 1690c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_rsp->scsi_status); 1691c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_rc = -EIO; 1692c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 1693c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "%s reset successful\n", desc); 1694c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1695c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1696c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1697c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1698c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rsp_rc; 1699c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1700c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1701c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1702c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_abort_task_set - Abort outstanding commands to the device 1703c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device to abort commands 1704c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1705c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * This sends an Abort Task Set to the VIOS for the specified device. This does 1706c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * NOT send any cancel to the VIOS. That must be done separately. 1707c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1708c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1709c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1710c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1711c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_abort_task_set(struct scsi_device *sdev) 1712c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1713c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 1714c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 1715c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_cmd *tmf; 1716c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt, *found_evt; 1717c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom union ibmvfc_iu rsp_iu; 1718c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; 1719c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_rc = -EBUSY; 1720c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 1721c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_code = 0; 1722c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1723c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1724c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom found_evt = NULL; 1725c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(evt, &vhost->sent, queue) { 1726c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd && evt->cmnd->device == sdev) { 1727c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom found_evt = evt; 1728c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1729c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1730c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1731c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1732c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!found_evt) { 1733c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) 1734c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); 1735c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1736c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1737c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1738c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1739c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->state == IBMVFC_ACTIVE) { 1740c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt = ibmvfc_get_event(vhost); 1741c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); 1742c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1743c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf = &evt->iu.cmd; 1744c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(tmf, 0, sizeof(*tmf)); 1745c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); 1746c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp.len = sizeof(tmf->rsp); 1747c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; 1748c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->payload_len = sizeof(tmf->iu); 1749c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->resp_len = sizeof(tmf->rsp); 1750c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->cancel_key = (unsigned long)sdev->hostdata; 1751c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->tgt_scsi_id = rport->port_id; 1752c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int_to_scsilun(sdev->lun, &tmf->iu.lun); 1753c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); 1754c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; 1755c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->sync_iu = &rsp_iu; 1756c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1757c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom init_completion(&evt->comp); 1758c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); 1759c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1760c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1761c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1762c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1763c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp_rc != 0) { 1764c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); 1765c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -EIO; 1766c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1767c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1768c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); 1769c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait_for_completion(&evt->comp); 1770c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1771c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp_iu.cmd.status) { 1772c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (fc_rsp->flags & FCP_RSP_LEN_VALID) 1773c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_code = fc_rsp->data.info.rsp_code; 1774c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1775c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " 1776c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "flags: %x fcp_rsp: %x, scsi_status: %x\n", 1777c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), 1778c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, 1779c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom fc_rsp->scsi_status); 1780c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_rc = -EIO; 1781c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 1782c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "Abort successful\n"); 1783c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1784c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1785c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1786c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1787c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rsp_rc; 1788c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1789c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1790c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1791c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_cancel_all - Cancel all outstanding commands to the device 1792c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device to cancel commands 1793c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @type: type of error recovery being performed 1794c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1795c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * This sends a cancel to the VIOS for the specified device. This does 1796c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * NOT send any abort to the actual device. That must be done separately. 1797c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1798c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1799c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / other on failure 1800c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1801c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_cancel_all(struct scsi_device *sdev, int type) 1802c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1803c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 1804c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_target *starget = scsi_target(sdev); 1805c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(starget); 1806c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_tmf *tmf; 1807c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt, *found_evt; 1808c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom union ibmvfc_iu rsp; 1809c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rsp_rc = -EBUSY; 1810c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 1811c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom u16 status; 1812c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1813c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 1814c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1815c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom found_evt = NULL; 1816c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(evt, &vhost->sent, queue) { 1817c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd && evt->cmnd->device == sdev) { 1818c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom found_evt = evt; 1819c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 1820c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1821c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1822c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1823c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!found_evt) { 1824c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) 1825c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "No events found to cancel\n"); 1826c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1827c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1828c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1829c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1830c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->state == IBMVFC_ACTIVE) { 1831c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt = ibmvfc_get_event(vhost); 1832c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); 1833c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1834c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf = &evt->iu.tmf; 1835c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom memset(tmf, 0, sizeof(*tmf)); 1836c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->common.version = 1; 1837c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->common.opcode = IBMVFC_TMF_MAD; 1838c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->common.length = sizeof(*tmf); 1839c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->scsi_id = rport->port_id; 1840c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int_to_scsilun(sdev->lun, &tmf->lun); 1841c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->flags = (type | IBMVFC_TMF_LUA_VALID); 1842c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->cancel_key = (unsigned long)sdev->hostdata; 1843c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tmf->my_cancel_key = (unsigned long)starget->hostdata; 1844c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1845c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->sync_iu = &rsp; 1846c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom init_completion(&evt->comp); 1847c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); 1848c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1849c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1850c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1851c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1852c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rsp_rc != 0) { 1853c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc); 1854c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -EIO; 1855c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1856c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1857c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n"); 1858c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1859c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait_for_completion(&evt->comp); 1860c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom status = rsp.mad_common.status; 1861c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1862c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_free_event(evt); 1863c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1864c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1865c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (status != IBMVFC_MAD_SUCCESS) { 1866c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status); 1867c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -EIO; 1868c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1869c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1870c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n"); 1871c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1872c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1873c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1874c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1875c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_match_target - Match function for specified target 1876c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 1877c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @device: device to match (starget) 1878c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1879c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1880c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1 if event matches starget / 0 if event does not match starget 1881c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1882c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) 1883c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1884c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd && scsi_target(evt->cmnd->device) == device) 1885c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 1; 1886c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1887c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1888c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1889c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1890c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_match_lun - Match function for specified LUN 1891c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @evt: ibmvfc event struct 1892c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @device: device to match (sdev) 1893c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1894c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1895c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1 if event matches sdev / 0 if event does not match sdev 1896c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1897c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) 1898c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1899c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (evt->cmnd && evt->cmnd->device == device) 1900c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 1; 1901c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 1902c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1903c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1904c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1905c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_wait_for_ops - Wait for ops to complete 1906c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 1907c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @device: device to match (starget or sdev) 1908c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @match: match function 1909c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1910c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1911c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * SUCCESS / FAILED 1912c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1913c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, 1914c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int (*match) (struct ibmvfc_event *, void *)) 1915c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1916c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt; 1917c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom DECLARE_COMPLETION_ONSTACK(comp); 1918c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int wait; 1919c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 1920c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom signed long timeout = init_timeout * HZ; 1921c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1922c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 1923c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom do { 1924c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait = 0; 1925c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1926c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(evt, &vhost->sent, queue) { 1927c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (match(evt, device)) { 1928c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->eh_comp = ∁ 1929c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait++; 1930c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1931c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1932c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1933c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1934c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (wait) { 1935c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom timeout = wait_for_completion_timeout(&comp, timeout); 1936c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1937c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!timeout) { 1938c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait = 0; 1939c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(vhost->host->host_lock, flags); 1940c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_for_each_entry(evt, &vhost->sent, queue) { 1941c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (match(evt, device)) { 1942c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->eh_comp = NULL; 1943c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom wait++; 1944c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1945c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1946c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(vhost->host->host_lock, flags); 1947c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (wait) 1948c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); 1949c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 1950c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return wait ? FAILED : SUCCESS; 1951c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1952c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 1953c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } while (wait); 1954c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1955c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 1956c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return SUCCESS; 1957c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1958c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1959c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1960c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_eh_abort_handler - Abort a command 1961c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @cmd: scsi command to abort 1962c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1963c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1964c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * SUCCESS / FAILED 1965c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1966c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) 1967c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1968c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_device *sdev = cmd->device; 1969c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 1970c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int cancel_rc, abort_rc; 1971c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = FAILED; 1972c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1973c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 1974c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_wait_while_resetting(vhost); 1975c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); 1976c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom abort_rc = ibmvfc_abort_task_set(sdev); 1977c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1978c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cancel_rc && !abort_rc) 1979c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); 1980c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1981c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 1982c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 1983c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 1984c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1985c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 1986c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_eh_device_reset_handler - Reset a single LUN 1987c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @cmd: scsi command struct 1988c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 1989c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 1990c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * SUCCESS / FAILED 1991c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 1992c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) 1993c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 1994c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_device *sdev = cmd->device; 1995c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 1996c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int cancel_rc, reset_rc; 1997c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = FAILED; 1998c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 1999c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 2000c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_wait_while_resetting(vhost); 2001c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); 2002c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); 2003c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2004c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cancel_rc && !reset_rc) 2005c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); 2006c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2007c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 2008c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 2009c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2010c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2011c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2012c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_dev_cancel_all - Device iterated cancel all function 2013c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device struct 2014c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @data: return code 2015c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2016c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2017c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_dev_cancel_all(struct scsi_device *sdev, void *data) 2018c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2019c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long *rc = data; 2020c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); 2021c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2022c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2023c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2024c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_dev_abort_all - Device iterated abort task set function 2025c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device struct 2026c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @data: return code 2027c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2028c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2029c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) 2030c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2031c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long *rc = data; 2032c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom *rc |= ibmvfc_abort_task_set(sdev); 2033c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2034c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2035c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2036c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_eh_target_reset_handler - Reset the target 2037c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @cmd: scsi command struct 2038c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2039c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 2040c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * SUCCESS / FAILED 2041c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2042c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) 2043c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2044c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_device *sdev = cmd->device; 2045c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(sdev->host); 2046c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_target *starget = scsi_target(sdev); 2047c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int reset_rc; 2048c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = FAILED; 2049c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long cancel_rc = 0; 2050c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2051c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 2052c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_wait_while_resetting(vhost); 2053c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); 2054c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); 2055c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2056c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cancel_rc && !reset_rc) 2057c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); 2058c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2059c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 2060c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc; 2061c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2062c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2063c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2064c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_eh_host_reset_handler - Reset the connection to the server 2065c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @cmd: struct scsi_cmnd having problems 2066c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2067c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2068c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) 2069c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2070c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc; 2071c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(cmd->device->host); 2072c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2073c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Resetting connection due to error recovery\n"); 2074c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_issue_fc_host_lip(vhost->host); 2075c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return rc ? FAILED : SUCCESS; 2076c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2077c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2078c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2079c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_terminate_rport_io - Terminate all pending I/O to the rport. 2080c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @rport: rport struct 2081c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2082c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 2083c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * none 2084c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2085c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_terminate_rport_io(struct fc_rport *rport) 2086c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2087c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct scsi_target *starget = to_scsi_target(&rport->dev); 2088c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 2089c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 2090c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long cancel_rc = 0; 2091c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long abort_rc = 0; 2092c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int rc = FAILED; 2093c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2094c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ENTER; 2095c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); 2096c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); 2097c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2098c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!cancel_rc && !abort_rc) 2099c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); 2100c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2101c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc == FAILED) 2102c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_issue_fc_host_lip(shost); 2103c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom LEAVE; 2104c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2105c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2106c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const struct { 2107c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom enum ibmvfc_async_event ae; 2108c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const char *desc; 2109c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} ae_desc [] = { 2110c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_ELS_PLOGI, "PLOGI" }, 2111c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_ELS_LOGO, "LOGO" }, 2112c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_ELS_PRLO, "PRLO" }, 2113c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_SCN_NPORT, "N-Port SCN" }, 2114c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_SCN_GROUP, "Group SCN" }, 2115c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_SCN_DOMAIN, "Domain SCN" }, 2116c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_SCN_FABRIC, "Fabric SCN" }, 2117c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_LINK_UP, "Link Up" }, 2118c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_LINK_DOWN, "Link Down" }, 2119c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_LINK_DEAD, "Link Dead" }, 2120c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_HALT, "Halt" }, 2121c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_RESUME, "Resume" }, 2122c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed" }, 2123c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 2124c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2125c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *unknown_ae = "Unknown async"; 2126c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2127c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2128c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_get_ae_desc - Get text description for async event 2129c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @ae: async event 2130c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2131c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2132c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic const char *ibmvfc_get_ae_desc(u64 ae) 2133c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2134c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int i; 2135c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2136c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom for (i = 0; i < ARRAY_SIZE(ae_desc); i++) 2137c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (ae_desc[i].ae == ae) 2138c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return ae_desc[i].desc; 2139c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2140c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return unknown_ae; 2141c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2142c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2143c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2144c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_handle_async - Handle an async event from the adapter 2145c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @crq: crq to process 2146c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 2147c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2148c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2149c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, 2150c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost) 2151c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2152c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom const char *desc = ibmvfc_get_ae_desc(crq->event); 2153c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2154c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx," 2155c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name); 2156c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2157c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (crq->event) { 2158c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_LINK_UP: 2159c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_RESUME: 2160c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->events_to_log |= IBMVFC_AE_LINKUP; 2161c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->delay_init = 1; 2162c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom __ibmvfc_reset_host(vhost); 2163c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2164c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_SCN_FABRIC: 2165c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_SCN_DOMAIN: 2166c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->events_to_log |= IBMVFC_AE_RSCN; 2167c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->delay_init = 1; 2168c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom __ibmvfc_reset_host(vhost); 2169c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2170c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_SCN_NPORT: 2171c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_SCN_GROUP: 2172c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->events_to_log |= IBMVFC_AE_RSCN; 2173c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_ELS_LOGO: 2174c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_ELS_PRLO: 2175c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_ELS_PLOGI: 2176c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_reinit_host(vhost); 2177c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2178c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_LINK_DOWN: 2179c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_ADAPTER_FAILED: 2180c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); 2181c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2182c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_LINK_DEAD: 2183c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 2184c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2185c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_AE_HALT: 2186c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_HALTED); 2187c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2188c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 2189c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event); 2190c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2191c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }; 2192c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2193c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2194c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2195c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_handle_crq - Handles and frees received events in the CRQ 2196c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @crq: Command/Response queue 2197c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @vhost: ibmvfc host struct 2198c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2199c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2200c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) 2201c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2202c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom long rc; 2203c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_event *evt = (struct ibmvfc_event *)crq->ioba; 2204c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2205c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (crq->valid) { 2206c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CRQ_INIT_RSP: 2207c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom switch (crq->format) { 2208c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CRQ_INIT: 2209c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_info(vhost->dev, "Partner initialized\n"); 2210c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* Send back a response */ 2211c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rc = ibmvfc_send_crq_init_complete(vhost); 2212c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (rc == 0) 2213c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_host(vhost, 0); 2214c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 2215c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc); 2216c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2217c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CRQ_INIT_COMPLETE: 2218c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_info(vhost->dev, "Partner initialization complete\n"); 2219c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_init_host(vhost, 0); 2220c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2221c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 2222c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format); 2223c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2224c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2225c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CRQ_XPORT_EVENT: 2226c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->state = IBMVFC_NO_CRQ; 2227c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 2228c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (crq->format == IBMVFC_PARTITION_MIGRATED) { 2229c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* We need to re-setup the interpartition connection */ 2230c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_info(vhost->dev, "Re-enabling adapter\n"); 2231c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->client_migrated = 1; 2232c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_purge_requests(vhost, DID_REQUEUE); 2233c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rc = ibmvfc_reenable_crq_queue(vhost)) || 2234c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (rc = ibmvfc_send_crq_init(vhost))) { 2235c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 2236c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc); 2237c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 2238c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); 2239c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else { 2240c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); 2241c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2242c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_purge_requests(vhost, DID_ERROR); 2243c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if ((rc = ibmvfc_reset_crq(vhost)) || 2244c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom (rc = ibmvfc_send_crq_init(vhost))) { 2245c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 2246c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc); 2247c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 2248c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); 2249c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2250c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2251c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom case IBMVFC_CRQ_CMD_RSP: 2252c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom break; 2253c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom default: 2254c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid); 2255c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2256c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2257c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2258c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (crq->format == IBMVFC_ASYNC_EVENT) 2259c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2260c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2261c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom /* The only kind of payload CRQs we should get are responses to 2262c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * things we send. Make sure this response is to something we 2263c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * actually sent 2264c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom */ 2265c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) { 2266c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n", 2267c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom crq->ioba); 2268c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2269c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2270c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2271c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (unlikely(atomic_read(&evt->free))) { 2272c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n", 2273c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom crq->ioba); 2274c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return; 2275c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2276c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2277c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom del_timer(&evt->timer); 2278c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom list_del(&evt->queue); 2279c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom ibmvfc_trc_end(evt); 2280c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom evt->done(evt); 2281c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2282c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2283c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2284c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_scan_finished - Check if the device scan is done. 2285c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @shost: scsi host struct 2286c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @time: current elapsed time 2287c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2288c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 2289c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 if scan is not done / 1 if scan is done 2290c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2291c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time) 2292c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2293c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags; 2294c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 2295c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom int done = 0; 2296c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2297c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 2298c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (time >= (init_timeout * HZ)) { 2299c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom dev_info(vhost->dev, "Scan taking longer than %d seconds, " 2300c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom "continuing initialization\n", init_timeout); 2301c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom done = 1; 2302c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } 2303c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2304c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) 2305c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom done = 1; 2306c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 2307c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return done; 2308c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2309c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2310c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2311c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_slave_alloc - Setup the device's task set value 2312c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: struct scsi_device device to configure 2313c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2314c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Set the device's task set value so that error handling works as 2315c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * expected. 2316c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2317c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 2318c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / -ENXIO if device does not exist 2319c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2320c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_slave_alloc(struct scsi_device *sdev) 2321c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2322c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = sdev->host; 2323c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 2324c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 2325c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags = 0; 2326c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2327c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (!rport || fc_remote_port_chkready(rport)) 2328c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return -ENXIO; 2329c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2330c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 2331c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev->hostdata = (void *)(unsigned long)vhost->task_set++; 2332c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 2333c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 2334c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2335c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2336c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2337c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_target_alloc - Setup the target's task set value 2338c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @starget: struct scsi_target 2339c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2340c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Set the target's task set value so that error handling works as 2341c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * expected. 2342c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2343c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 2344c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 on success / -ENXIO if device does not exist 2345c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2346c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_target_alloc(struct scsi_target *starget) 2347c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2348c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 2349c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 2350c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags = 0; 2351c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2352c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 2353c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom starget->hostdata = (void *)(unsigned long)vhost->task_set++; 2354c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 2355c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 2356c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2357c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2358c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2359c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_slave_configure - Configure the device 2360c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: struct scsi_device device to configure 2361c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2362c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Enable allow_restart for a device if it is a disk. Adjust the 2363c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * queue_depth here also. 2364c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2365c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Returns: 2366c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 0 2367c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2368c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_slave_configure(struct scsi_device *sdev) 2369c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2370c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = sdev->host; 2371c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct fc_rport *rport = starget_to_rport(sdev->sdev_target); 2372c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom unsigned long flags = 0; 2373c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2374c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_lock_irqsave(shost->host_lock, flags); 2375c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (sdev->type == TYPE_DISK) 2376c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom sdev->allow_restart = 1; 2377c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2378c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (sdev->tagged_supported) { 2379c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); 2380c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_activate_tcq(sdev, sdev->queue_depth); 2381c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 2382c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_deactivate_tcq(sdev, sdev->queue_depth); 2383c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2384c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom rport->dev_loss_tmo = dev_loss_tmo; 2385c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom spin_unlock_irqrestore(shost->host_lock, flags); 2386c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return 0; 2387c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2388c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2389c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2390c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_change_queue_depth - Change the device's queue depth 2391c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device struct 2392c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @qdepth: depth to set 2393c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2394c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 2395c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * actual depth set 2396c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2397c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth) 2398c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2399c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) 2400c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom qdepth = IBMVFC_MAX_CMDS_PER_LUN; 2401c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2402c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_adjust_queue_depth(sdev, 0, qdepth); 2403c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return sdev->queue_depth; 2404c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2405c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2406c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom/** 2407c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * ibmvfc_change_queue_type - Change the device's queue type 2408c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @sdev: scsi device struct 2409c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * @tag_type: type of tags to use 2410c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * 2411c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * Return value: 2412c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom * actual queue type set 2413c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom **/ 2414c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic int ibmvfc_change_queue_type(struct scsi_device *sdev, int tag_type) 2415c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom{ 2416c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (sdev->tagged_supported) { 2417c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_set_tag_type(sdev, tag_type); 2418c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2419c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom if (tag_type) 2420c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_activate_tcq(sdev, sdev->queue_depth); 2421c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom else 2422c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom scsi_deactivate_tcq(sdev, sdev->queue_depth); 2423c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom } else 2424c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom tag_type = 0; 2425c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2426c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return tag_type; 2427c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2428c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2429c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic ssize_t ibmvfc_show_host_partition_name(struct device *dev, 2430c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct device_attribute *attr, char *buf) 2431b3003be36a3c9215cd17182349981581de269048Casey Leedom{ 2432c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct Scsi_Host *shost = class_to_shost(dev); 2433c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom struct ibmvfc_host *vhost = shost_priv(shost); 2434c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2435c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom return snprintf(buf, PAGE_SIZE, "%s\n", 2436c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom vhost->login_buf->resp.partition_name); 2437c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom} 2438c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom 2439c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedomstatic struct device_attribute ibmvfc_host_partition_name = { 2440c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom .attr = { 2441c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom .name = "partition_name", 2442c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom .mode = S_IRUGO, 2443c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom }, 2444c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom .show = ibmvfc_show_host_partition_name, 2445c6e0d91464da214081af546496dd3a4b6d19db70Casey Leedom}; 2446 2447static ssize_t ibmvfc_show_host_device_name(struct device *dev, 2448 struct device_attribute *attr, char *buf) 2449{ 2450 struct Scsi_Host *shost = class_to_shost(dev); 2451 struct ibmvfc_host *vhost = shost_priv(shost); 2452 2453 return snprintf(buf, PAGE_SIZE, "%s\n", 2454 vhost->login_buf->resp.device_name); 2455} 2456 2457static struct device_attribute ibmvfc_host_device_name = { 2458 .attr = { 2459 .name = "device_name", 2460 .mode = S_IRUGO, 2461 }, 2462 .show = ibmvfc_show_host_device_name, 2463}; 2464 2465static ssize_t ibmvfc_show_host_loc_code(struct device *dev, 2466 struct device_attribute *attr, char *buf) 2467{ 2468 struct Scsi_Host *shost = class_to_shost(dev); 2469 struct ibmvfc_host *vhost = shost_priv(shost); 2470 2471 return snprintf(buf, PAGE_SIZE, "%s\n", 2472 vhost->login_buf->resp.port_loc_code); 2473} 2474 2475static struct device_attribute ibmvfc_host_loc_code = { 2476 .attr = { 2477 .name = "port_loc_code", 2478 .mode = S_IRUGO, 2479 }, 2480 .show = ibmvfc_show_host_loc_code, 2481}; 2482 2483static ssize_t ibmvfc_show_host_drc_name(struct device *dev, 2484 struct device_attribute *attr, char *buf) 2485{ 2486 struct Scsi_Host *shost = class_to_shost(dev); 2487 struct ibmvfc_host *vhost = shost_priv(shost); 2488 2489 return snprintf(buf, PAGE_SIZE, "%s\n", 2490 vhost->login_buf->resp.drc_name); 2491} 2492 2493static struct device_attribute ibmvfc_host_drc_name = { 2494 .attr = { 2495 .name = "drc_name", 2496 .mode = S_IRUGO, 2497 }, 2498 .show = ibmvfc_show_host_drc_name, 2499}; 2500 2501static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, 2502 struct device_attribute *attr, char *buf) 2503{ 2504 struct Scsi_Host *shost = class_to_shost(dev); 2505 struct ibmvfc_host *vhost = shost_priv(shost); 2506 return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); 2507} 2508 2509static struct device_attribute ibmvfc_host_npiv_version = { 2510 .attr = { 2511 .name = "npiv_version", 2512 .mode = S_IRUGO, 2513 }, 2514 .show = ibmvfc_show_host_npiv_version, 2515}; 2516 2517/** 2518 * ibmvfc_show_log_level - Show the adapter's error logging level 2519 * @dev: class device struct 2520 * @buf: buffer 2521 * 2522 * Return value: 2523 * number of bytes printed to buffer 2524 **/ 2525static ssize_t ibmvfc_show_log_level(struct device *dev, 2526 struct device_attribute *attr, char *buf) 2527{ 2528 struct Scsi_Host *shost = class_to_shost(dev); 2529 struct ibmvfc_host *vhost = shost_priv(shost); 2530 unsigned long flags = 0; 2531 int len; 2532 2533 spin_lock_irqsave(shost->host_lock, flags); 2534 len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->log_level); 2535 spin_unlock_irqrestore(shost->host_lock, flags); 2536 return len; 2537} 2538 2539/** 2540 * ibmvfc_store_log_level - Change the adapter's error logging level 2541 * @dev: class device struct 2542 * @buf: buffer 2543 * 2544 * Return value: 2545 * number of bytes printed to buffer 2546 **/ 2547static ssize_t ibmvfc_store_log_level(struct device *dev, 2548 struct device_attribute *attr, 2549 const char *buf, size_t count) 2550{ 2551 struct Scsi_Host *shost = class_to_shost(dev); 2552 struct ibmvfc_host *vhost = shost_priv(shost); 2553 unsigned long flags = 0; 2554 2555 spin_lock_irqsave(shost->host_lock, flags); 2556 vhost->log_level = simple_strtoul(buf, NULL, 10); 2557 spin_unlock_irqrestore(shost->host_lock, flags); 2558 return strlen(buf); 2559} 2560 2561static struct device_attribute ibmvfc_log_level_attr = { 2562 .attr = { 2563 .name = "log_level", 2564 .mode = S_IRUGO | S_IWUSR, 2565 }, 2566 .show = ibmvfc_show_log_level, 2567 .store = ibmvfc_store_log_level 2568}; 2569 2570#ifdef CONFIG_SCSI_IBMVFC_TRACE 2571/** 2572 * ibmvfc_read_trace - Dump the adapter trace 2573 * @kobj: kobject struct 2574 * @bin_attr: bin_attribute struct 2575 * @buf: buffer 2576 * @off: offset 2577 * @count: buffer size 2578 * 2579 * Return value: 2580 * number of bytes printed to buffer 2581 **/ 2582static ssize_t ibmvfc_read_trace(struct kobject *kobj, 2583 struct bin_attribute *bin_attr, 2584 char *buf, loff_t off, size_t count) 2585{ 2586 struct device *dev = container_of(kobj, struct device, kobj); 2587 struct Scsi_Host *shost = class_to_shost(dev); 2588 struct ibmvfc_host *vhost = shost_priv(shost); 2589 unsigned long flags = 0; 2590 int size = IBMVFC_TRACE_SIZE; 2591 char *src = (char *)vhost->trace; 2592 2593 if (off > size) 2594 return 0; 2595 if (off + count > size) { 2596 size -= off; 2597 count = size; 2598 } 2599 2600 spin_lock_irqsave(shost->host_lock, flags); 2601 memcpy(buf, &src[off], count); 2602 spin_unlock_irqrestore(shost->host_lock, flags); 2603 return count; 2604} 2605 2606static struct bin_attribute ibmvfc_trace_attr = { 2607 .attr = { 2608 .name = "trace", 2609 .mode = S_IRUGO, 2610 }, 2611 .size = 0, 2612 .read = ibmvfc_read_trace, 2613}; 2614#endif 2615 2616static struct device_attribute *ibmvfc_attrs[] = { 2617 &ibmvfc_host_partition_name, 2618 &ibmvfc_host_device_name, 2619 &ibmvfc_host_loc_code, 2620 &ibmvfc_host_drc_name, 2621 &ibmvfc_host_npiv_version, 2622 &ibmvfc_log_level_attr, 2623 NULL 2624}; 2625 2626static struct scsi_host_template driver_template = { 2627 .module = THIS_MODULE, 2628 .name = "IBM POWER Virtual FC Adapter", 2629 .proc_name = IBMVFC_NAME, 2630 .queuecommand = ibmvfc_queuecommand, 2631 .eh_abort_handler = ibmvfc_eh_abort_handler, 2632 .eh_device_reset_handler = ibmvfc_eh_device_reset_handler, 2633 .eh_target_reset_handler = ibmvfc_eh_target_reset_handler, 2634 .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, 2635 .slave_alloc = ibmvfc_slave_alloc, 2636 .slave_configure = ibmvfc_slave_configure, 2637 .target_alloc = ibmvfc_target_alloc, 2638 .scan_finished = ibmvfc_scan_finished, 2639 .change_queue_depth = ibmvfc_change_queue_depth, 2640 .change_queue_type = ibmvfc_change_queue_type, 2641 .cmd_per_lun = 16, 2642 .can_queue = IBMVFC_MAX_REQUESTS_DEFAULT, 2643 .this_id = -1, 2644 .sg_tablesize = SG_ALL, 2645 .max_sectors = IBMVFC_MAX_SECTORS, 2646 .use_clustering = ENABLE_CLUSTERING, 2647 .shost_attrs = ibmvfc_attrs, 2648}; 2649 2650/** 2651 * ibmvfc_next_async_crq - Returns the next entry in async queue 2652 * @vhost: ibmvfc host struct 2653 * 2654 * Returns: 2655 * Pointer to next entry in queue / NULL if empty 2656 **/ 2657static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost) 2658{ 2659 struct ibmvfc_async_crq_queue *async_crq = &vhost->async_crq; 2660 struct ibmvfc_async_crq *crq; 2661 2662 crq = &async_crq->msgs[async_crq->cur]; 2663 if (crq->valid & 0x80) { 2664 if (++async_crq->cur == async_crq->size) 2665 async_crq->cur = 0; 2666 } else 2667 crq = NULL; 2668 2669 return crq; 2670} 2671 2672/** 2673 * ibmvfc_next_crq - Returns the next entry in message queue 2674 * @vhost: ibmvfc host struct 2675 * 2676 * Returns: 2677 * Pointer to next entry in queue / NULL if empty 2678 **/ 2679static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost) 2680{ 2681 struct ibmvfc_crq_queue *queue = &vhost->crq; 2682 struct ibmvfc_crq *crq; 2683 2684 crq = &queue->msgs[queue->cur]; 2685 if (crq->valid & 0x80) { 2686 if (++queue->cur == queue->size) 2687 queue->cur = 0; 2688 } else 2689 crq = NULL; 2690 2691 return crq; 2692} 2693 2694/** 2695 * ibmvfc_interrupt - Interrupt handler 2696 * @irq: number of irq to handle, not used 2697 * @dev_instance: ibmvfc_host that received interrupt 2698 * 2699 * Returns: 2700 * IRQ_HANDLED 2701 **/ 2702static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) 2703{ 2704 struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; 2705 struct vio_dev *vdev = to_vio_dev(vhost->dev); 2706 struct ibmvfc_crq *crq; 2707 struct ibmvfc_async_crq *async; 2708 unsigned long flags; 2709 int done = 0; 2710 2711 spin_lock_irqsave(vhost->host->host_lock, flags); 2712 vio_disable_interrupts(to_vio_dev(vhost->dev)); 2713 while (!done) { 2714 /* Pull all the valid messages off the CRQ */ 2715 while ((crq = ibmvfc_next_crq(vhost)) != NULL) { 2716 ibmvfc_handle_crq(crq, vhost); 2717 crq->valid = 0; 2718 } 2719 2720 /* Pull all the valid messages off the async CRQ */ 2721 while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { 2722 ibmvfc_handle_async(async, vhost); 2723 async->valid = 0; 2724 } 2725 2726 vio_enable_interrupts(vdev); 2727 if ((crq = ibmvfc_next_crq(vhost)) != NULL) { 2728 vio_disable_interrupts(vdev); 2729 ibmvfc_handle_crq(crq, vhost); 2730 crq->valid = 0; 2731 } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { 2732 vio_disable_interrupts(vdev); 2733 ibmvfc_handle_async(async, vhost); 2734 async->valid = 0; 2735 } else 2736 done = 1; 2737 } 2738 2739 spin_unlock_irqrestore(vhost->host->host_lock, flags); 2740 return IRQ_HANDLED; 2741} 2742 2743/** 2744 * ibmvfc_init_tgt - Set the next init job step for the target 2745 * @tgt: ibmvfc target struct 2746 * @job_step: job step to perform 2747 * 2748 **/ 2749static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, 2750 void (*job_step) (struct ibmvfc_target *)) 2751{ 2752 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); 2753 tgt->job_step = job_step; 2754 wake_up(&tgt->vhost->work_wait_q); 2755} 2756 2757/** 2758 * ibmvfc_retry_tgt_init - Attempt to retry a step in target initialization 2759 * @tgt: ibmvfc target struct 2760 * @job_step: initialization job step 2761 * 2762 **/ 2763static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, 2764 void (*job_step) (struct ibmvfc_target *)) 2765{ 2766 if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { 2767 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 2768 wake_up(&tgt->vhost->work_wait_q); 2769 } else 2770 ibmvfc_init_tgt(tgt, job_step); 2771} 2772 2773/** 2774 * ibmvfc_tgt_prli_done - Completion handler for Process Login 2775 * @evt: ibmvfc event struct 2776 * 2777 **/ 2778static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) 2779{ 2780 struct ibmvfc_target *tgt = evt->tgt; 2781 struct ibmvfc_host *vhost = evt->vhost; 2782 struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; 2783 u32 status = rsp->common.status; 2784 2785 vhost->discovery_threads--; 2786 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 2787 switch (status) { 2788 case IBMVFC_MAD_SUCCESS: 2789 tgt_dbg(tgt, "Process Login succeeded\n"); 2790 tgt->need_login = 0; 2791 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); 2792 break; 2793 case IBMVFC_MAD_DRIVER_FAILED: 2794 break; 2795 case IBMVFC_MAD_CRQ_ERROR: 2796 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); 2797 break; 2798 case IBMVFC_MAD_FAILED: 2799 default: 2800 tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n", 2801 ibmvfc_get_cmd_error(rsp->status, rsp->error), 2802 rsp->status, rsp->error, status); 2803 if (ibmvfc_retry_cmd(rsp->status, rsp->error)) 2804 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); 2805 else 2806 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 2807 break; 2808 }; 2809 2810 kref_put(&tgt->kref, ibmvfc_release_tgt); 2811 ibmvfc_free_event(evt); 2812 wake_up(&vhost->work_wait_q); 2813} 2814 2815/** 2816 * ibmvfc_tgt_send_prli - Send a process login 2817 * @tgt: ibmvfc target struct 2818 * 2819 **/ 2820static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) 2821{ 2822 struct ibmvfc_process_login *prli; 2823 struct ibmvfc_host *vhost = tgt->vhost; 2824 struct ibmvfc_event *evt; 2825 2826 if (vhost->discovery_threads >= disc_threads) 2827 return; 2828 2829 kref_get(&tgt->kref); 2830 evt = ibmvfc_get_event(vhost); 2831 vhost->discovery_threads++; 2832 ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT); 2833 evt->tgt = tgt; 2834 prli = &evt->iu.prli; 2835 memset(prli, 0, sizeof(*prli)); 2836 prli->common.version = 1; 2837 prli->common.opcode = IBMVFC_PROCESS_LOGIN; 2838 prli->common.length = sizeof(*prli); 2839 prli->scsi_id = tgt->scsi_id; 2840 2841 prli->parms.type = IBMVFC_SCSI_FCP_TYPE; 2842 prli->parms.flags = IBMVFC_PRLI_EST_IMG_PAIR; 2843 prli->parms.service_parms = IBMVFC_PRLI_INITIATOR_FUNC; 2844 2845 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); 2846 if (ibmvfc_send_event(evt, vhost, default_timeout)) { 2847 vhost->discovery_threads--; 2848 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 2849 kref_put(&tgt->kref, ibmvfc_release_tgt); 2850 } else 2851 tgt_dbg(tgt, "Sent process login\n"); 2852} 2853 2854/** 2855 * ibmvfc_tgt_plogi_done - Completion handler for Port Login 2856 * @evt: ibmvfc event struct 2857 * 2858 **/ 2859static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) 2860{ 2861 struct ibmvfc_target *tgt = evt->tgt; 2862 struct ibmvfc_host *vhost = evt->vhost; 2863 struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi; 2864 u32 status = rsp->common.status; 2865 2866 vhost->discovery_threads--; 2867 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 2868 switch (status) { 2869 case IBMVFC_MAD_SUCCESS: 2870 tgt_dbg(tgt, "Port Login succeeded\n"); 2871 if (tgt->ids.port_name && 2872 tgt->ids.port_name != wwn_to_u64(rsp->service_parms.port_name)) { 2873 vhost->reinit = 1; 2874 tgt_dbg(tgt, "Port re-init required\n"); 2875 break; 2876 } 2877 tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); 2878 tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); 2879 tgt->ids.port_id = tgt->scsi_id; 2880 tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET; 2881 memcpy(&tgt->service_parms, &rsp->service_parms, 2882 sizeof(tgt->service_parms)); 2883 memcpy(&tgt->service_parms_change, &rsp->service_parms_change, 2884 sizeof(tgt->service_parms_change)); 2885 ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli); 2886 break; 2887 case IBMVFC_MAD_DRIVER_FAILED: 2888 break; 2889 case IBMVFC_MAD_CRQ_ERROR: 2890 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); 2891 break; 2892 case IBMVFC_MAD_FAILED: 2893 default: 2894 tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", 2895 ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, 2896 ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, 2897 ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); 2898 2899 if (ibmvfc_retry_cmd(rsp->status, rsp->error)) 2900 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); 2901 else 2902 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 2903 break; 2904 }; 2905 2906 kref_put(&tgt->kref, ibmvfc_release_tgt); 2907 ibmvfc_free_event(evt); 2908 wake_up(&vhost->work_wait_q); 2909} 2910 2911/** 2912 * ibmvfc_tgt_send_plogi - Send PLOGI to the specified target 2913 * @tgt: ibmvfc target struct 2914 * 2915 **/ 2916static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) 2917{ 2918 struct ibmvfc_port_login *plogi; 2919 struct ibmvfc_host *vhost = tgt->vhost; 2920 struct ibmvfc_event *evt; 2921 2922 if (vhost->discovery_threads >= disc_threads) 2923 return; 2924 2925 kref_get(&tgt->kref); 2926 evt = ibmvfc_get_event(vhost); 2927 vhost->discovery_threads++; 2928 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); 2929 ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT); 2930 evt->tgt = tgt; 2931 plogi = &evt->iu.plogi; 2932 memset(plogi, 0, sizeof(*plogi)); 2933 plogi->common.version = 1; 2934 plogi->common.opcode = IBMVFC_PORT_LOGIN; 2935 plogi->common.length = sizeof(*plogi); 2936 plogi->scsi_id = tgt->scsi_id; 2937 2938 if (ibmvfc_send_event(evt, vhost, default_timeout)) { 2939 vhost->discovery_threads--; 2940 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 2941 kref_put(&tgt->kref, ibmvfc_release_tgt); 2942 } else 2943 tgt_dbg(tgt, "Sent port login\n"); 2944} 2945 2946/** 2947 * ibmvfc_tgt_implicit_logout_done - Completion handler for Implicit Logout MAD 2948 * @evt: ibmvfc event struct 2949 * 2950 **/ 2951static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) 2952{ 2953 struct ibmvfc_target *tgt = evt->tgt; 2954 struct ibmvfc_host *vhost = evt->vhost; 2955 struct ibmvfc_implicit_logout *rsp = &evt->xfer_iu->implicit_logout; 2956 u32 status = rsp->common.status; 2957 2958 vhost->discovery_threads--; 2959 ibmvfc_free_event(evt); 2960 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 2961 2962 switch (status) { 2963 case IBMVFC_MAD_SUCCESS: 2964 tgt_dbg(tgt, "Implicit Logout succeeded\n"); 2965 break; 2966 case IBMVFC_MAD_DRIVER_FAILED: 2967 kref_put(&tgt->kref, ibmvfc_release_tgt); 2968 wake_up(&vhost->work_wait_q); 2969 return; 2970 case IBMVFC_MAD_FAILED: 2971 default: 2972 tgt_err(tgt, "Implicit Logout failed: rc=0x%02X\n", status); 2973 break; 2974 }; 2975 2976 if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) 2977 ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); 2978 else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && 2979 tgt->scsi_id != tgt->new_scsi_id) 2980 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 2981 kref_put(&tgt->kref, ibmvfc_release_tgt); 2982 wake_up(&vhost->work_wait_q); 2983} 2984 2985/** 2986 * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target 2987 * @tgt: ibmvfc target struct 2988 * 2989 **/ 2990static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) 2991{ 2992 struct ibmvfc_implicit_logout *mad; 2993 struct ibmvfc_host *vhost = tgt->vhost; 2994 struct ibmvfc_event *evt; 2995 2996 if (vhost->discovery_threads >= disc_threads) 2997 return; 2998 2999 kref_get(&tgt->kref); 3000 evt = ibmvfc_get_event(vhost); 3001 vhost->discovery_threads++; 3002 ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); 3003 evt->tgt = tgt; 3004 mad = &evt->iu.implicit_logout; 3005 memset(mad, 0, sizeof(*mad)); 3006 mad->common.version = 1; 3007 mad->common.opcode = IBMVFC_IMPLICIT_LOGOUT; 3008 mad->common.length = sizeof(*mad); 3009 mad->old_scsi_id = tgt->scsi_id; 3010 3011 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); 3012 if (ibmvfc_send_event(evt, vhost, default_timeout)) { 3013 vhost->discovery_threads--; 3014 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3015 kref_put(&tgt->kref, ibmvfc_release_tgt); 3016 } else 3017 tgt_dbg(tgt, "Sent Implicit Logout\n"); 3018} 3019 3020/** 3021 * ibmvfc_adisc_needs_plogi - Does device need PLOGI? 3022 * @mad: ibmvfc passthru mad struct 3023 * @tgt: ibmvfc target struct 3024 * 3025 * Returns: 3026 * 1 if PLOGI needed / 0 if PLOGI not needed 3027 **/ 3028static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad, 3029 struct ibmvfc_target *tgt) 3030{ 3031 if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name, 3032 sizeof(tgt->ids.port_name))) 3033 return 1; 3034 if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name, 3035 sizeof(tgt->ids.node_name))) 3036 return 1; 3037 if (mad->fc_iu.response[6] != tgt->scsi_id) 3038 return 1; 3039 return 0; 3040} 3041 3042/** 3043 * ibmvfc_tgt_adisc_done - Completion handler for ADISC 3044 * @evt: ibmvfc event struct 3045 * 3046 **/ 3047static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) 3048{ 3049 struct ibmvfc_target *tgt = evt->tgt; 3050 struct ibmvfc_host *vhost = evt->vhost; 3051 struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; 3052 u32 status = mad->common.status; 3053 u8 fc_reason, fc_explain; 3054 3055 vhost->discovery_threads--; 3056 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3057 3058 switch (status) { 3059 case IBMVFC_MAD_SUCCESS: 3060 tgt_dbg(tgt, "ADISC succeeded\n"); 3061 if (ibmvfc_adisc_needs_plogi(mad, tgt)) 3062 tgt->need_login = 1; 3063 break; 3064 case IBMVFC_MAD_DRIVER_FAILED: 3065 break; 3066 case IBMVFC_MAD_FAILED: 3067 default: 3068 tgt->need_login = 1; 3069 fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16; 3070 fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8; 3071 tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", 3072 ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error), 3073 mad->iu.status, mad->iu.error, 3074 ibmvfc_get_fc_type(fc_reason), fc_reason, 3075 ibmvfc_get_ls_explain(fc_explain), fc_explain, status); 3076 break; 3077 }; 3078 3079 kref_put(&tgt->kref, ibmvfc_release_tgt); 3080 ibmvfc_free_event(evt); 3081 wake_up(&vhost->work_wait_q); 3082} 3083 3084/** 3085 * ibmvfc_init_passthru - Initialize an event struct for FC passthru 3086 * @evt: ibmvfc event struct 3087 * 3088 **/ 3089static void ibmvfc_init_passthru(struct ibmvfc_event *evt) 3090{ 3091 struct ibmvfc_passthru_mad *mad = &evt->iu.passthru; 3092 3093 memset(mad, 0, sizeof(*mad)); 3094 mad->common.version = 1; 3095 mad->common.opcode = IBMVFC_PASSTHRU; 3096 mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu); 3097 mad->cmd_ioba.va = (u64)evt->crq.ioba + 3098 offsetof(struct ibmvfc_passthru_mad, iu); 3099 mad->cmd_ioba.len = sizeof(mad->iu); 3100 mad->iu.cmd_len = sizeof(mad->fc_iu.payload); 3101 mad->iu.rsp_len = sizeof(mad->fc_iu.response); 3102 mad->iu.cmd.va = (u64)evt->crq.ioba + 3103 offsetof(struct ibmvfc_passthru_mad, fc_iu) + 3104 offsetof(struct ibmvfc_passthru_fc_iu, payload); 3105 mad->iu.cmd.len = sizeof(mad->fc_iu.payload); 3106 mad->iu.rsp.va = (u64)evt->crq.ioba + 3107 offsetof(struct ibmvfc_passthru_mad, fc_iu) + 3108 offsetof(struct ibmvfc_passthru_fc_iu, response); 3109 mad->iu.rsp.len = sizeof(mad->fc_iu.response); 3110} 3111 3112/** 3113 * ibmvfc_tgt_adisc - Initiate an ADISC for specified target 3114 * @tgt: ibmvfc target struct 3115 * 3116 **/ 3117static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) 3118{ 3119 struct ibmvfc_passthru_mad *mad; 3120 struct ibmvfc_host *vhost = tgt->vhost; 3121 struct ibmvfc_event *evt; 3122 3123 if (vhost->discovery_threads >= disc_threads) 3124 return; 3125 3126 kref_get(&tgt->kref); 3127 evt = ibmvfc_get_event(vhost); 3128 vhost->discovery_threads++; 3129 ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT); 3130 evt->tgt = tgt; 3131 3132 ibmvfc_init_passthru(evt); 3133 mad = &evt->iu.passthru; 3134 mad->iu.flags = IBMVFC_FC_ELS; 3135 mad->iu.scsi_id = tgt->scsi_id; 3136 3137 mad->fc_iu.payload[0] = IBMVFC_ADISC; 3138 memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, 3139 sizeof(vhost->login_buf->resp.port_name)); 3140 memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name, 3141 sizeof(vhost->login_buf->resp.node_name)); 3142 mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; 3143 3144 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); 3145 if (ibmvfc_send_event(evt, vhost, default_timeout)) { 3146 vhost->discovery_threads--; 3147 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3148 kref_put(&tgt->kref, ibmvfc_release_tgt); 3149 } else 3150 tgt_dbg(tgt, "Sent ADISC\n"); 3151} 3152 3153/** 3154 * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD 3155 * @evt: ibmvfc event struct 3156 * 3157 **/ 3158static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) 3159{ 3160 struct ibmvfc_target *tgt = evt->tgt; 3161 struct ibmvfc_host *vhost = evt->vhost; 3162 struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt; 3163 u32 status = rsp->common.status; 3164 3165 vhost->discovery_threads--; 3166 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3167 switch (status) { 3168 case IBMVFC_MAD_SUCCESS: 3169 tgt_dbg(tgt, "Query Target succeeded\n"); 3170 tgt->new_scsi_id = rsp->scsi_id; 3171 if (rsp->scsi_id != tgt->scsi_id) 3172 ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); 3173 else 3174 ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); 3175 break; 3176 case IBMVFC_MAD_DRIVER_FAILED: 3177 break; 3178 case IBMVFC_MAD_CRQ_ERROR: 3179 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); 3180 break; 3181 case IBMVFC_MAD_FAILED: 3182 default: 3183 tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", 3184 ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, 3185 ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, 3186 ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); 3187 3188 if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && 3189 rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ && 3190 rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG) 3191 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 3192 else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) 3193 ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); 3194 else 3195 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 3196 break; 3197 }; 3198 3199 kref_put(&tgt->kref, ibmvfc_release_tgt); 3200 ibmvfc_free_event(evt); 3201 wake_up(&vhost->work_wait_q); 3202} 3203 3204/** 3205 * ibmvfc_tgt_query_target - Initiate a Query Target for specified target 3206 * @tgt: ibmvfc target struct 3207 * 3208 **/ 3209static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt) 3210{ 3211 struct ibmvfc_query_tgt *query_tgt; 3212 struct ibmvfc_host *vhost = tgt->vhost; 3213 struct ibmvfc_event *evt; 3214 3215 if (vhost->discovery_threads >= disc_threads) 3216 return; 3217 3218 kref_get(&tgt->kref); 3219 evt = ibmvfc_get_event(vhost); 3220 vhost->discovery_threads++; 3221 evt->tgt = tgt; 3222 ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT); 3223 query_tgt = &evt->iu.query_tgt; 3224 memset(query_tgt, 0, sizeof(*query_tgt)); 3225 query_tgt->common.version = 1; 3226 query_tgt->common.opcode = IBMVFC_QUERY_TARGET; 3227 query_tgt->common.length = sizeof(*query_tgt); 3228 query_tgt->wwpn = tgt->ids.port_name; 3229 3230 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); 3231 if (ibmvfc_send_event(evt, vhost, default_timeout)) { 3232 vhost->discovery_threads--; 3233 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3234 kref_put(&tgt->kref, ibmvfc_release_tgt); 3235 } else 3236 tgt_dbg(tgt, "Sent Query Target\n"); 3237} 3238 3239/** 3240 * ibmvfc_alloc_target - Allocate and initialize an ibmvfc target 3241 * @vhost: ibmvfc host struct 3242 * @scsi_id: SCSI ID to allocate target for 3243 * 3244 * Returns: 3245 * 0 on success / other on failure 3246 **/ 3247static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) 3248{ 3249 struct ibmvfc_target *tgt; 3250 unsigned long flags; 3251 3252 spin_lock_irqsave(vhost->host->host_lock, flags); 3253 list_for_each_entry(tgt, &vhost->targets, queue) { 3254 if (tgt->scsi_id == scsi_id) { 3255 if (tgt->need_login) 3256 ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); 3257 goto unlock_out; 3258 } 3259 } 3260 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3261 3262 tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL); 3263 if (!tgt) { 3264 dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n", 3265 scsi_id); 3266 return -ENOMEM; 3267 } 3268 3269 tgt->scsi_id = scsi_id; 3270 tgt->new_scsi_id = scsi_id; 3271 tgt->vhost = vhost; 3272 tgt->need_login = 1; 3273 kref_init(&tgt->kref); 3274 ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); 3275 spin_lock_irqsave(vhost->host->host_lock, flags); 3276 list_add_tail(&tgt->queue, &vhost->targets); 3277 3278unlock_out: 3279 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3280 return 0; 3281} 3282 3283/** 3284 * ibmvfc_alloc_targets - Allocate and initialize ibmvfc targets 3285 * @vhost: ibmvfc host struct 3286 * 3287 * Returns: 3288 * 0 on success / other on failure 3289 **/ 3290static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost) 3291{ 3292 int i, rc; 3293 3294 for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) 3295 rc = ibmvfc_alloc_target(vhost, 3296 vhost->disc_buf->scsi_id[i] & IBMVFC_DISC_TGT_SCSI_ID_MASK); 3297 3298 return rc; 3299} 3300 3301/** 3302 * ibmvfc_discover_targets_done - Completion handler for discover targets MAD 3303 * @evt: ibmvfc event struct 3304 * 3305 **/ 3306static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) 3307{ 3308 struct ibmvfc_host *vhost = evt->vhost; 3309 struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets; 3310 u32 mad_status = rsp->common.status; 3311 3312 switch (mad_status) { 3313 case IBMVFC_MAD_SUCCESS: 3314 ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); 3315 vhost->num_targets = rsp->num_written; 3316 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); 3317 break; 3318 case IBMVFC_MAD_FAILED: 3319 dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n", 3320 ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); 3321 ibmvfc_retry_host_init(vhost); 3322 break; 3323 case IBMVFC_MAD_DRIVER_FAILED: 3324 break; 3325 default: 3326 dev_err(vhost->dev, "Invalid Discover Targets response: 0x%x\n", mad_status); 3327 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3328 break; 3329 } 3330 3331 ibmvfc_free_event(evt); 3332 wake_up(&vhost->work_wait_q); 3333} 3334 3335/** 3336 * ibmvfc_discover_targets - Send Discover Targets MAD 3337 * @vhost: ibmvfc host struct 3338 * 3339 **/ 3340static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) 3341{ 3342 struct ibmvfc_discover_targets *mad; 3343 struct ibmvfc_event *evt = ibmvfc_get_event(vhost); 3344 3345 ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT); 3346 mad = &evt->iu.discover_targets; 3347 memset(mad, 0, sizeof(*mad)); 3348 mad->common.version = 1; 3349 mad->common.opcode = IBMVFC_DISC_TARGETS; 3350 mad->common.length = sizeof(*mad); 3351 mad->bufflen = vhost->disc_buf_sz; 3352 mad->buffer.va = vhost->disc_buf_dma; 3353 mad->buffer.len = vhost->disc_buf_sz; 3354 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); 3355 3356 if (!ibmvfc_send_event(evt, vhost, default_timeout)) 3357 ibmvfc_dbg(vhost, "Sent discover targets\n"); 3358 else 3359 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3360} 3361 3362/** 3363 * ibmvfc_npiv_login_done - Completion handler for NPIV Login 3364 * @evt: ibmvfc event struct 3365 * 3366 **/ 3367static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) 3368{ 3369 struct ibmvfc_host *vhost = evt->vhost; 3370 u32 mad_status = evt->xfer_iu->npiv_login.common.status; 3371 struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp; 3372 unsigned int npiv_max_sectors; 3373 3374 switch (mad_status) { 3375 case IBMVFC_MAD_SUCCESS: 3376 ibmvfc_free_event(evt); 3377 break; 3378 case IBMVFC_MAD_FAILED: 3379 dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n", 3380 ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); 3381 if (ibmvfc_retry_cmd(rsp->status, rsp->error)) 3382 ibmvfc_retry_host_init(vhost); 3383 else 3384 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3385 ibmvfc_free_event(evt); 3386 return; 3387 case IBMVFC_MAD_CRQ_ERROR: 3388 ibmvfc_retry_host_init(vhost); 3389 case IBMVFC_MAD_DRIVER_FAILED: 3390 ibmvfc_free_event(evt); 3391 return; 3392 default: 3393 dev_err(vhost->dev, "Invalid NPIV Login response: 0x%x\n", mad_status); 3394 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3395 ibmvfc_free_event(evt); 3396 return; 3397 } 3398 3399 vhost->client_migrated = 0; 3400 3401 if (!(rsp->flags & IBMVFC_NATIVE_FC)) { 3402 dev_err(vhost->dev, "Virtual adapter does not support FC. %x\n", 3403 rsp->flags); 3404 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3405 wake_up(&vhost->work_wait_q); 3406 return; 3407 } 3408 3409 if (rsp->max_cmds <= IBMVFC_NUM_INTERNAL_REQ) { 3410 dev_err(vhost->dev, "Virtual adapter supported queue depth too small: %d\n", 3411 rsp->max_cmds); 3412 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3413 wake_up(&vhost->work_wait_q); 3414 return; 3415 } 3416 3417 npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); 3418 dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", 3419 rsp->partition_name, rsp->device_name, rsp->port_loc_code, 3420 rsp->drc_name, npiv_max_sectors); 3421 3422 fc_host_fabric_name(vhost->host) = rsp->node_name; 3423 fc_host_node_name(vhost->host) = rsp->node_name; 3424 fc_host_port_name(vhost->host) = rsp->port_name; 3425 fc_host_port_id(vhost->host) = rsp->scsi_id; 3426 fc_host_port_type(vhost->host) = FC_PORTTYPE_NPIV; 3427 fc_host_supported_classes(vhost->host) = 0; 3428 if (rsp->service_parms.class1_parms[0] & 0x80000000) 3429 fc_host_supported_classes(vhost->host) |= FC_COS_CLASS1; 3430 if (rsp->service_parms.class2_parms[0] & 0x80000000) 3431 fc_host_supported_classes(vhost->host) |= FC_COS_CLASS2; 3432 if (rsp->service_parms.class3_parms[0] & 0x80000000) 3433 fc_host_supported_classes(vhost->host) |= FC_COS_CLASS3; 3434 fc_host_maxframe_size(vhost->host) = 3435 rsp->service_parms.common.bb_rcv_sz & 0x0fff; 3436 3437 vhost->host->can_queue = rsp->max_cmds - IBMVFC_NUM_INTERNAL_REQ; 3438 vhost->host->max_sectors = npiv_max_sectors; 3439 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); 3440 wake_up(&vhost->work_wait_q); 3441} 3442 3443/** 3444 * ibmvfc_npiv_login - Sends NPIV login 3445 * @vhost: ibmvfc host struct 3446 * 3447 **/ 3448static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) 3449{ 3450 struct ibmvfc_npiv_login_mad *mad; 3451 struct ibmvfc_event *evt = ibmvfc_get_event(vhost); 3452 3453 ibmvfc_gather_partition_info(vhost); 3454 ibmvfc_set_login_info(vhost); 3455 ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT); 3456 3457 memcpy(vhost->login_buf, &vhost->login_info, sizeof(vhost->login_info)); 3458 mad = &evt->iu.npiv_login; 3459 memset(mad, 0, sizeof(struct ibmvfc_npiv_login_mad)); 3460 mad->common.version = 1; 3461 mad->common.opcode = IBMVFC_NPIV_LOGIN; 3462 mad->common.length = sizeof(struct ibmvfc_npiv_login_mad); 3463 mad->buffer.va = vhost->login_buf_dma; 3464 mad->buffer.len = sizeof(*vhost->login_buf); 3465 3466 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); 3467 3468 if (!ibmvfc_send_event(evt, vhost, default_timeout)) 3469 ibmvfc_dbg(vhost, "Sent NPIV login\n"); 3470 else 3471 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); 3472}; 3473 3474/** 3475 * ibmvfc_dev_init_to_do - Is there target initialization work to do? 3476 * @vhost: ibmvfc host struct 3477 * 3478 * Returns: 3479 * 1 if work to do / 0 if not 3480 **/ 3481static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) 3482{ 3483 struct ibmvfc_target *tgt; 3484 3485 list_for_each_entry(tgt, &vhost->targets, queue) { 3486 if (tgt->action == IBMVFC_TGT_ACTION_INIT || 3487 tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) 3488 return 1; 3489 } 3490 3491 return 0; 3492} 3493 3494/** 3495 * __ibmvfc_work_to_do - Is there task level work to do? (no locking) 3496 * @vhost: ibmvfc host struct 3497 * 3498 * Returns: 3499 * 1 if work to do / 0 if not 3500 **/ 3501static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) 3502{ 3503 struct ibmvfc_target *tgt; 3504 3505 if (kthread_should_stop()) 3506 return 1; 3507 switch (vhost->action) { 3508 case IBMVFC_HOST_ACTION_NONE: 3509 case IBMVFC_HOST_ACTION_INIT_WAIT: 3510 return 0; 3511 case IBMVFC_HOST_ACTION_TGT_INIT: 3512 case IBMVFC_HOST_ACTION_QUERY_TGTS: 3513 if (vhost->discovery_threads == disc_threads) 3514 return 0; 3515 list_for_each_entry(tgt, &vhost->targets, queue) 3516 if (tgt->action == IBMVFC_TGT_ACTION_INIT) 3517 return 1; 3518 list_for_each_entry(tgt, &vhost->targets, queue) 3519 if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) 3520 return 0; 3521 return 1; 3522 case IBMVFC_HOST_ACTION_INIT: 3523 case IBMVFC_HOST_ACTION_ALLOC_TGTS: 3524 case IBMVFC_HOST_ACTION_TGT_ADD: 3525 case IBMVFC_HOST_ACTION_TGT_DEL: 3526 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 3527 case IBMVFC_HOST_ACTION_QUERY: 3528 default: 3529 break; 3530 }; 3531 3532 return 1; 3533} 3534 3535/** 3536 * ibmvfc_work_to_do - Is there task level work to do? 3537 * @vhost: ibmvfc host struct 3538 * 3539 * Returns: 3540 * 1 if work to do / 0 if not 3541 **/ 3542static int ibmvfc_work_to_do(struct ibmvfc_host *vhost) 3543{ 3544 unsigned long flags; 3545 int rc; 3546 3547 spin_lock_irqsave(vhost->host->host_lock, flags); 3548 rc = __ibmvfc_work_to_do(vhost); 3549 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3550 return rc; 3551} 3552 3553/** 3554 * ibmvfc_log_ae - Log async events if necessary 3555 * @vhost: ibmvfc host struct 3556 * @events: events to log 3557 * 3558 **/ 3559static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) 3560{ 3561 if (events & IBMVFC_AE_RSCN) 3562 fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_RSCN, 0); 3563 if ((events & IBMVFC_AE_LINKDOWN) && 3564 vhost->state >= IBMVFC_HALTED) 3565 fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); 3566 if ((events & IBMVFC_AE_LINKUP) && 3567 vhost->state == IBMVFC_INITIALIZING) 3568 fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKUP, 0); 3569} 3570 3571/** 3572 * ibmvfc_tgt_add_rport - Tell the FC transport about a new remote port 3573 * @tgt: ibmvfc target struct 3574 * 3575 **/ 3576static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) 3577{ 3578 struct ibmvfc_host *vhost = tgt->vhost; 3579 struct fc_rport *rport; 3580 unsigned long flags; 3581 3582 tgt_dbg(tgt, "Adding rport\n"); 3583 rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); 3584 spin_lock_irqsave(vhost->host->host_lock, flags); 3585 tgt->rport = rport; 3586 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3587 if (rport) { 3588 tgt_dbg(tgt, "rport add succeeded\n"); 3589 rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; 3590 rport->supported_classes = 0; 3591 tgt->target_id = rport->scsi_target_id; 3592 if (tgt->service_parms.class1_parms[0] & 0x80000000) 3593 rport->supported_classes |= FC_COS_CLASS1; 3594 if (tgt->service_parms.class2_parms[0] & 0x80000000) 3595 rport->supported_classes |= FC_COS_CLASS2; 3596 if (tgt->service_parms.class3_parms[0] & 0x80000000) 3597 rport->supported_classes |= FC_COS_CLASS3; 3598 } else 3599 tgt_dbg(tgt, "rport add failed\n"); 3600 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3601} 3602 3603/** 3604 * ibmvfc_do_work - Do task level work 3605 * @vhost: ibmvfc host struct 3606 * 3607 **/ 3608static void ibmvfc_do_work(struct ibmvfc_host *vhost) 3609{ 3610 struct ibmvfc_target *tgt; 3611 unsigned long flags; 3612 struct fc_rport *rport; 3613 3614 ibmvfc_log_ae(vhost, vhost->events_to_log); 3615 spin_lock_irqsave(vhost->host->host_lock, flags); 3616 vhost->events_to_log = 0; 3617 switch (vhost->action) { 3618 case IBMVFC_HOST_ACTION_NONE: 3619 case IBMVFC_HOST_ACTION_INIT_WAIT: 3620 break; 3621 case IBMVFC_HOST_ACTION_INIT: 3622 BUG_ON(vhost->state != IBMVFC_INITIALIZING); 3623 if (vhost->delay_init) { 3624 vhost->delay_init = 0; 3625 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3626 ssleep(15); 3627 return; 3628 } else 3629 vhost->job_step(vhost); 3630 break; 3631 case IBMVFC_HOST_ACTION_QUERY: 3632 list_for_each_entry(tgt, &vhost->targets, queue) 3633 ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target); 3634 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY_TGTS); 3635 break; 3636 case IBMVFC_HOST_ACTION_QUERY_TGTS: 3637 list_for_each_entry(tgt, &vhost->targets, queue) { 3638 if (tgt->action == IBMVFC_TGT_ACTION_INIT) { 3639 tgt->job_step(tgt); 3640 break; 3641 } 3642 } 3643 3644 if (!ibmvfc_dev_init_to_do(vhost)) 3645 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); 3646 break; 3647 case IBMVFC_HOST_ACTION_TGT_DEL: 3648 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 3649 list_for_each_entry(tgt, &vhost->targets, queue) { 3650 if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { 3651 tgt_dbg(tgt, "Deleting rport\n"); 3652 rport = tgt->rport; 3653 tgt->rport = NULL; 3654 list_del(&tgt->queue); 3655 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3656 if (rport) 3657 fc_remote_port_delete(rport); 3658 kref_put(&tgt->kref, ibmvfc_release_tgt); 3659 return; 3660 } 3661 } 3662 3663 if (vhost->state == IBMVFC_INITIALIZING) { 3664 if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { 3665 ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); 3666 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); 3667 vhost->init_retries = 0; 3668 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3669 scsi_unblock_requests(vhost->host); 3670 return; 3671 } else { 3672 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); 3673 vhost->job_step = ibmvfc_discover_targets; 3674 } 3675 } else { 3676 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 3677 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3678 scsi_unblock_requests(vhost->host); 3679 wake_up(&vhost->init_wait_q); 3680 return; 3681 } 3682 break; 3683 case IBMVFC_HOST_ACTION_ALLOC_TGTS: 3684 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_INIT); 3685 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3686 ibmvfc_alloc_targets(vhost); 3687 spin_lock_irqsave(vhost->host->host_lock, flags); 3688 break; 3689 case IBMVFC_HOST_ACTION_TGT_INIT: 3690 list_for_each_entry(tgt, &vhost->targets, queue) { 3691 if (tgt->action == IBMVFC_TGT_ACTION_INIT) { 3692 tgt->job_step(tgt); 3693 break; 3694 } 3695 } 3696 3697 if (!ibmvfc_dev_init_to_do(vhost)) 3698 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); 3699 break; 3700 case IBMVFC_HOST_ACTION_TGT_ADD: 3701 list_for_each_entry(tgt, &vhost->targets, queue) { 3702 if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) { 3703 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3704 ibmvfc_tgt_add_rport(tgt); 3705 return; 3706 } 3707 } 3708 3709 if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { 3710 vhost->reinit = 0; 3711 scsi_block_requests(vhost->host); 3712 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); 3713 } else { 3714 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 3715 wake_up(&vhost->init_wait_q); 3716 } 3717 break; 3718 default: 3719 break; 3720 }; 3721 3722 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3723} 3724 3725/** 3726 * ibmvfc_work - Do task level work 3727 * @data: ibmvfc host struct 3728 * 3729 * Returns: 3730 * zero 3731 **/ 3732static int ibmvfc_work(void *data) 3733{ 3734 struct ibmvfc_host *vhost = data; 3735 int rc; 3736 3737 set_user_nice(current, -20); 3738 3739 while (1) { 3740 rc = wait_event_interruptible(vhost->work_wait_q, 3741 ibmvfc_work_to_do(vhost)); 3742 3743 BUG_ON(rc); 3744 3745 if (kthread_should_stop()) 3746 break; 3747 3748 ibmvfc_do_work(vhost); 3749 } 3750 3751 ibmvfc_dbg(vhost, "ibmvfc kthread exiting...\n"); 3752 return 0; 3753} 3754 3755/** 3756 * ibmvfc_init_crq - Initializes and registers CRQ with hypervisor 3757 * @vhost: ibmvfc host struct 3758 * 3759 * Allocates a page for messages, maps it for dma, and registers 3760 * the crq with the hypervisor. 3761 * 3762 * Return value: 3763 * zero on success / other on failure 3764 **/ 3765static int ibmvfc_init_crq(struct ibmvfc_host *vhost) 3766{ 3767 int rc, retrc = -ENOMEM; 3768 struct device *dev = vhost->dev; 3769 struct vio_dev *vdev = to_vio_dev(dev); 3770 struct ibmvfc_crq_queue *crq = &vhost->crq; 3771 3772 ENTER; 3773 crq->msgs = (struct ibmvfc_crq *)get_zeroed_page(GFP_KERNEL); 3774 3775 if (!crq->msgs) 3776 return -ENOMEM; 3777 3778 crq->size = PAGE_SIZE / sizeof(*crq->msgs); 3779 crq->msg_token = dma_map_single(dev, crq->msgs, 3780 PAGE_SIZE, DMA_BIDIRECTIONAL); 3781 3782 if (dma_mapping_error(dev, crq->msg_token)) 3783 goto map_failed; 3784 3785 retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, 3786 crq->msg_token, PAGE_SIZE); 3787 3788 if (rc == H_RESOURCE) 3789 /* maybe kexecing and resource is busy. try a reset */ 3790 retrc = rc = ibmvfc_reset_crq(vhost); 3791 3792 if (rc == H_CLOSED) 3793 dev_warn(dev, "Partner adapter not ready\n"); 3794 else if (rc) { 3795 dev_warn(dev, "Error %d opening adapter\n", rc); 3796 goto reg_crq_failed; 3797 } 3798 3799 retrc = 0; 3800 3801 if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { 3802 dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); 3803 goto req_irq_failed; 3804 } 3805 3806 if ((rc = vio_enable_interrupts(vdev))) { 3807 dev_err(dev, "Error %d enabling interrupts\n", rc); 3808 goto req_irq_failed; 3809 } 3810 3811 crq->cur = 0; 3812 LEAVE; 3813 return retrc; 3814 3815req_irq_failed: 3816 do { 3817 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 3818 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 3819reg_crq_failed: 3820 dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); 3821map_failed: 3822 free_page((unsigned long)crq->msgs); 3823 return retrc; 3824} 3825 3826/** 3827 * ibmvfc_free_mem - Free memory for vhost 3828 * @vhost: ibmvfc host struct 3829 * 3830 * Return value: 3831 * none 3832 **/ 3833static void ibmvfc_free_mem(struct ibmvfc_host *vhost) 3834{ 3835 struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; 3836 3837 ENTER; 3838 mempool_destroy(vhost->tgt_pool); 3839 kfree(vhost->trace); 3840 dma_free_coherent(vhost->dev, vhost->disc_buf_sz, vhost->disc_buf, 3841 vhost->disc_buf_dma); 3842 dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf), 3843 vhost->login_buf, vhost->login_buf_dma); 3844 dma_pool_destroy(vhost->sg_pool); 3845 dma_unmap_single(vhost->dev, async_q->msg_token, 3846 async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); 3847 free_page((unsigned long)async_q->msgs); 3848 LEAVE; 3849} 3850 3851/** 3852 * ibmvfc_alloc_mem - Allocate memory for vhost 3853 * @vhost: ibmvfc host struct 3854 * 3855 * Return value: 3856 * 0 on success / non-zero on failure 3857 **/ 3858static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) 3859{ 3860 struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; 3861 struct device *dev = vhost->dev; 3862 3863 ENTER; 3864 async_q->msgs = (struct ibmvfc_async_crq *)get_zeroed_page(GFP_KERNEL); 3865 if (!async_q->msgs) { 3866 dev_err(dev, "Couldn't allocate async queue.\n"); 3867 goto nomem; 3868 } 3869 3870 async_q->size = PAGE_SIZE / sizeof(struct ibmvfc_async_crq); 3871 async_q->msg_token = dma_map_single(dev, async_q->msgs, 3872 async_q->size * sizeof(*async_q->msgs), 3873 DMA_BIDIRECTIONAL); 3874 3875 if (dma_mapping_error(dev, async_q->msg_token)) { 3876 dev_err(dev, "Failed to map async queue\n"); 3877 goto free_async_crq; 3878 } 3879 3880 vhost->sg_pool = dma_pool_create(IBMVFC_NAME, dev, 3881 SG_ALL * sizeof(struct srp_direct_buf), 3882 sizeof(struct srp_direct_buf), 0); 3883 3884 if (!vhost->sg_pool) { 3885 dev_err(dev, "Failed to allocate sg pool\n"); 3886 goto unmap_async_crq; 3887 } 3888 3889 vhost->login_buf = dma_alloc_coherent(dev, sizeof(*vhost->login_buf), 3890 &vhost->login_buf_dma, GFP_KERNEL); 3891 3892 if (!vhost->login_buf) { 3893 dev_err(dev, "Couldn't allocate NPIV login buffer\n"); 3894 goto free_sg_pool; 3895 } 3896 3897 vhost->disc_buf_sz = sizeof(vhost->disc_buf->scsi_id[0]) * max_targets; 3898 vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz, 3899 &vhost->disc_buf_dma, GFP_KERNEL); 3900 3901 if (!vhost->disc_buf) { 3902 dev_err(dev, "Couldn't allocate Discover Targets buffer\n"); 3903 goto free_login_buffer; 3904 } 3905 3906 vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, 3907 sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); 3908 3909 if (!vhost->trace) 3910 goto free_disc_buffer; 3911 3912 vhost->tgt_pool = mempool_create_kzalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, 3913 sizeof(struct ibmvfc_target)); 3914 3915 if (!vhost->tgt_pool) { 3916 dev_err(dev, "Couldn't allocate target memory pool\n"); 3917 goto free_trace; 3918 } 3919 3920 LEAVE; 3921 return 0; 3922 3923free_trace: 3924 kfree(vhost->trace); 3925free_disc_buffer: 3926 dma_free_coherent(dev, vhost->disc_buf_sz, vhost->disc_buf, 3927 vhost->disc_buf_dma); 3928free_login_buffer: 3929 dma_free_coherent(dev, sizeof(*vhost->login_buf), 3930 vhost->login_buf, vhost->login_buf_dma); 3931free_sg_pool: 3932 dma_pool_destroy(vhost->sg_pool); 3933unmap_async_crq: 3934 dma_unmap_single(dev, async_q->msg_token, 3935 async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); 3936free_async_crq: 3937 free_page((unsigned long)async_q->msgs); 3938nomem: 3939 LEAVE; 3940 return -ENOMEM; 3941} 3942 3943/** 3944 * ibmvfc_probe - Adapter hot plug add entry point 3945 * @vdev: vio device struct 3946 * @id: vio device id struct 3947 * 3948 * Return value: 3949 * 0 on success / non-zero on failure 3950 **/ 3951static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) 3952{ 3953 struct ibmvfc_host *vhost; 3954 struct Scsi_Host *shost; 3955 struct device *dev = &vdev->dev; 3956 int rc = -ENOMEM; 3957 3958 ENTER; 3959 shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); 3960 if (!shost) { 3961 dev_err(dev, "Couldn't allocate host data\n"); 3962 goto out; 3963 } 3964 3965 shost->transportt = ibmvfc_transport_template; 3966 shost->can_queue = max_requests; 3967 shost->max_lun = max_lun; 3968 shost->max_id = max_targets; 3969 shost->max_sectors = IBMVFC_MAX_SECTORS; 3970 shost->max_cmd_len = IBMVFC_MAX_CDB_LEN; 3971 shost->unique_id = shost->host_no; 3972 3973 vhost = shost_priv(shost); 3974 INIT_LIST_HEAD(&vhost->sent); 3975 INIT_LIST_HEAD(&vhost->free); 3976 INIT_LIST_HEAD(&vhost->targets); 3977 sprintf(vhost->name, IBMVFC_NAME); 3978 vhost->host = shost; 3979 vhost->dev = dev; 3980 vhost->partition_number = -1; 3981 vhost->log_level = log_level; 3982 strcpy(vhost->partition_name, "UNKNOWN"); 3983 init_waitqueue_head(&vhost->work_wait_q); 3984 init_waitqueue_head(&vhost->init_wait_q); 3985 3986 if ((rc = ibmvfc_alloc_mem(vhost))) 3987 goto free_scsi_host; 3988 3989 vhost->work_thread = kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NAME, 3990 shost->host_no); 3991 3992 if (IS_ERR(vhost->work_thread)) { 3993 dev_err(dev, "Couldn't create kernel thread: %ld\n", 3994 PTR_ERR(vhost->work_thread)); 3995 goto free_host_mem; 3996 } 3997 3998 if ((rc = ibmvfc_init_crq(vhost))) { 3999 dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); 4000 goto kill_kthread; 4001 } 4002 4003 if ((rc = ibmvfc_init_event_pool(vhost))) { 4004 dev_err(dev, "Couldn't initialize event pool. rc=%d\n", rc); 4005 goto release_crq; 4006 } 4007 4008 if ((rc = scsi_add_host(shost, dev))) 4009 goto release_event_pool; 4010 4011 if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj, 4012 &ibmvfc_trace_attr))) { 4013 dev_err(dev, "Failed to create trace file. rc=%d\n", rc); 4014 goto remove_shost; 4015 } 4016 4017 dev_set_drvdata(dev, vhost); 4018 spin_lock(&ibmvfc_driver_lock); 4019 list_add_tail(&vhost->queue, &ibmvfc_head); 4020 spin_unlock(&ibmvfc_driver_lock); 4021 4022 ibmvfc_send_crq_init(vhost); 4023 scsi_scan_host(shost); 4024 return 0; 4025 4026remove_shost: 4027 scsi_remove_host(shost); 4028release_event_pool: 4029 ibmvfc_free_event_pool(vhost); 4030release_crq: 4031 ibmvfc_release_crq_queue(vhost); 4032kill_kthread: 4033 kthread_stop(vhost->work_thread); 4034free_host_mem: 4035 ibmvfc_free_mem(vhost); 4036free_scsi_host: 4037 scsi_host_put(shost); 4038out: 4039 LEAVE; 4040 return rc; 4041} 4042 4043/** 4044 * ibmvfc_remove - Adapter hot plug remove entry point 4045 * @vdev: vio device struct 4046 * 4047 * Return value: 4048 * 0 4049 **/ 4050static int ibmvfc_remove(struct vio_dev *vdev) 4051{ 4052 struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev); 4053 unsigned long flags; 4054 4055 ENTER; 4056 ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); 4057 ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); 4058 ibmvfc_wait_while_resetting(vhost); 4059 ibmvfc_release_crq_queue(vhost); 4060 kthread_stop(vhost->work_thread); 4061 fc_remove_host(vhost->host); 4062 scsi_remove_host(vhost->host); 4063 4064 spin_lock_irqsave(vhost->host->host_lock, flags); 4065 ibmvfc_purge_requests(vhost, DID_ERROR); 4066 ibmvfc_free_event_pool(vhost); 4067 spin_unlock_irqrestore(vhost->host->host_lock, flags); 4068 4069 ibmvfc_free_mem(vhost); 4070 spin_lock(&ibmvfc_driver_lock); 4071 list_del(&vhost->queue); 4072 spin_unlock(&ibmvfc_driver_lock); 4073 scsi_host_put(vhost->host); 4074 LEAVE; 4075 return 0; 4076} 4077 4078/** 4079 * ibmvfc_get_desired_dma - Calculate DMA resources needed by the driver 4080 * @vdev: vio device struct 4081 * 4082 * Return value: 4083 * Number of bytes the driver will need to DMA map at the same time in 4084 * order to perform well. 4085 */ 4086static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev) 4087{ 4088 unsigned long pool_dma = max_requests * sizeof(union ibmvfc_iu); 4089 return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun); 4090} 4091 4092static struct vio_device_id ibmvfc_device_table[] __devinitdata = { 4093 {"fcp", "IBM,vfc-client"}, 4094 { "", "" } 4095}; 4096MODULE_DEVICE_TABLE(vio, ibmvfc_device_table); 4097 4098static struct vio_driver ibmvfc_driver = { 4099 .id_table = ibmvfc_device_table, 4100 .probe = ibmvfc_probe, 4101 .remove = ibmvfc_remove, 4102 .get_desired_dma = ibmvfc_get_desired_dma, 4103 .driver = { 4104 .name = IBMVFC_NAME, 4105 .owner = THIS_MODULE, 4106 } 4107}; 4108 4109static struct fc_function_template ibmvfc_transport_functions = { 4110 .show_host_fabric_name = 1, 4111 .show_host_node_name = 1, 4112 .show_host_port_name = 1, 4113 .show_host_supported_classes = 1, 4114 .show_host_port_type = 1, 4115 .show_host_port_id = 1, 4116 4117 .get_host_port_state = ibmvfc_get_host_port_state, 4118 .show_host_port_state = 1, 4119 4120 .get_host_speed = ibmvfc_get_host_speed, 4121 .show_host_speed = 1, 4122 4123 .issue_fc_host_lip = ibmvfc_issue_fc_host_lip, 4124 .terminate_rport_io = ibmvfc_terminate_rport_io, 4125 4126 .show_rport_maxframe_size = 1, 4127 .show_rport_supported_classes = 1, 4128 4129 .set_rport_dev_loss_tmo = ibmvfc_set_rport_dev_loss_tmo, 4130 .show_rport_dev_loss_tmo = 1, 4131 4132 .get_starget_node_name = ibmvfc_get_starget_node_name, 4133 .show_starget_node_name = 1, 4134 4135 .get_starget_port_name = ibmvfc_get_starget_port_name, 4136 .show_starget_port_name = 1, 4137 4138 .get_starget_port_id = ibmvfc_get_starget_port_id, 4139 .show_starget_port_id = 1, 4140}; 4141 4142/** 4143 * ibmvfc_module_init - Initialize the ibmvfc module 4144 * 4145 * Return value: 4146 * 0 on success / other on failure 4147 **/ 4148static int __init ibmvfc_module_init(void) 4149{ 4150 int rc; 4151 4152 if (!firmware_has_feature(FW_FEATURE_VIO)) 4153 return -ENODEV; 4154 4155 printk(KERN_INFO IBMVFC_NAME": IBM Virtual Fibre Channel Driver version: %s %s\n", 4156 IBMVFC_DRIVER_VERSION, IBMVFC_DRIVER_DATE); 4157 4158 ibmvfc_transport_template = fc_attach_transport(&ibmvfc_transport_functions); 4159 if (!ibmvfc_transport_template) 4160 return -ENOMEM; 4161 4162 rc = vio_register_driver(&ibmvfc_driver); 4163 if (rc) 4164 fc_release_transport(ibmvfc_transport_template); 4165 return rc; 4166} 4167 4168/** 4169 * ibmvfc_module_exit - Teardown the ibmvfc module 4170 * 4171 * Return value: 4172 * nothing 4173 **/ 4174static void __exit ibmvfc_module_exit(void) 4175{ 4176 vio_unregister_driver(&ibmvfc_driver); 4177 fc_release_transport(ibmvfc_transport_template); 4178} 4179 4180module_init(ibmvfc_module_init); 4181module_exit(ibmvfc_module_exit); 4182