11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright IBM Corporation 1994, 2004
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          Santiago Leon (santil@us.ibm.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          Dave Boutcher (sleddog@us.ibm.com)
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USA
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Emulation of a SCSI host adapter for Virtual I/O devices
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver supports the SCSI adapter implemented by the IBM
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power5 firmware.  That SCSI adapter is not a physical adapter,
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but allows Linux SCSI peripheral drivers to directly
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * access devices in another logical partition on the physical system.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The virtual adapter(s) are present in the open firmware device
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tree just like real adapters.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One of the capabilities provided on these systems is the ability
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to DMA between partitions.  The architecture states that for VSCSI,
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the server side is allowed to DMA to and from the client.  The client
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is never trusted to DMA to or from the server directly.
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Messages are sent between partitions on a "Command/Response Queue"
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (CRQ), which is just a buffer of 16 byte entries in the receiver's
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Senders cannot access the buffer directly, but send messages by
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * making a hypervisor call and passing in the 16 bytes.  The hypervisor
439b7dac086bec7c71722d6e79464609e17f0996e7Bart Van Assche * puts the message in the next 16 byte space in round-robin fashion,
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * turns on the high order bit of the message (the valid bit), and
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generates an interrupt to the receiver (if interrupts are turned on.)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The receiver just turns off the valid bit when they have copied out
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the message.
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (IU) (as defined in the T10 standard available at www.t10.org), gets
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a DMA address for the message, and sends it to the server as the
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * payload of a CRQ message.  The server DMAs the SRP IU and processes it,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including doing any additional data transfers.  When it is done, it
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMAs the SRP response back to the same address as the request came from,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and sends a CRQ message back to inform the client that the request has
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completed.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
587834799a6c8fed36d06d6b78bfd17831ecfa93c4Stephen Rothwell * TODO: This is currently pretty tied to the IBM pSeries hypervisor
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interfaces.  It would be really nice to abstract this above an RDMA
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * layer.
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
675a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
68126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King#include <linux/of.h>
6964355b929dec0cb6271e4ac7834c9cf262961e40Brian King#include <linux/pm.h>
700f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King#include <linux/kthread.h>
71d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse#include <asm/firmware.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/vio.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h>
774d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori#include <scsi/scsi_transport_srp.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ibmvscsi.h"
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The values below are somewhat arbitrary default values, but
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that there are 3 bits of channel value, 6 bits of id, and
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5 bits of LUN.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_id = 64;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_channel = 3;
87e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int init_timeout = 300;
88e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int login_timeout = 60;
89e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int info_timeout = 30;
90e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int abort_timeout = 60;
91e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int reset_timeout = 60;
92a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jenningsstatic int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
934f10aae0d1a285df6b16bf6ca5abd366140fd371Brian Kingstatic int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
94c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic int fast_fail = 1;
95126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic int client_reserve = 1;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
974d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonoristatic struct scsi_transport_template *ibmvscsi_transport_template;
984d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
99aac3118d33e275a7b1134cb19227c982f4d43877Brian King#define IBMVSCSI_VERSION "1.5.9"
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhousestatic struct ibmvscsi_ops *ibmvscsi_ops;
102d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("IBM Virtual SCSI");
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Dave Boutcher");
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(IBMVSCSI_VERSION);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_id, "Largest ID value for each channel");
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_channel, "Largest channel value");
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
11421465eda9eafa275ed11c27779d90aa95559b6f6Brian Kingmodule_param_named(max_requests, max_requests, int, S_IRUGO);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
116c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsmodule_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
117c1988e3123751fd425fbae99d5c1776608e965a9Robert JenningsMODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
118126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingmodule_param_named(client_reserve, client_reserve, int, S_IRUGO );
119126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian KingMODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for the event pool and event structs
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialize_event_pool: - Allocates and initializes the event pool for a host
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool to be initialized
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @size:	Number of events in pool
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data who owns the event pool
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero on success.
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int initialize_event_pool(struct event_pool *pool,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 int size, struct ibmvscsi_host_data *hostdata)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->size = size;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->next = 0;
1394c021dd136c0ad524e6d117296beafad2bf570c0FUJITA Tomonori	pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pool->events)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->iu_storage =
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    dma_alloc_coherent(hostdata->dev,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       pool->size * sizeof(*pool->iu_storage),
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       &pool->iu_token, 0);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pool->iu_storage) {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(pool->events);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < pool->size; ++i) {
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct srp_event_struct *evt = &pool->events[i];
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(&evt->crq, 0x00, sizeof(evt->crq));
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set(&evt->free, 1);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.valid = 0x80;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.IU_length = sizeof(*evt->xfer_iu);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.IU_data_ptr = pool->iu_token +
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sizeof(*evt->xfer_iu) * i;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->xfer_iu = pool->iu_storage + i;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->hostdata = hostdata;
1624dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		evt->ext_list = NULL;
1634dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		evt->ext_list_token = 0;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release_event_pool: - Frees memory of an event pool of a host
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool to be released
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data who owns the even pool
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero on success.
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void release_event_pool(struct event_pool *pool,
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct ibmvscsi_host_data *hostdata)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, in_use = 0;
1804dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	for (i = 0; i < pool->size; ++i) {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&pool->events[i].free) != 1)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			++in_use;
1834dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		if (pool->events[i].ext_list) {
1844dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			dma_free_coherent(hostdata->dev,
185ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori				  SG_ALL * sizeof(struct srp_direct_buf),
1864dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				  pool->events[i].ext_list,
1874dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				  pool->events[i].ext_list_token);
1884dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		}
1894dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_use)
1916c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_warn(hostdata->dev, "releasing event pool with %d "
1926c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 "events still in use?\n", in_use);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(pool->events);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(hostdata->dev,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  pool->size * sizeof(*pool->iu_storage),
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  pool->iu_storage, pool->iu_token);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * valid_event_struct: - Determines if event is valid.
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the event
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:	srp_event_struct to be checked for validity
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero if event is invalid, one otherwise.
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int valid_event_struct(struct event_pool *pool,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct srp_event_struct *evt)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = evt - pool->events;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (index < 0 || index >= pool->size)	/* outside of bounds */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt != pool->events + index)	/* unaligned */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_free-event_struct: - Changes status of event to "free"
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the event
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:	srp_event_struct to be modified
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void free_event_struct(struct event_pool *pool,
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       struct srp_event_struct *evt)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!valid_event_struct(pool, evt)) {
2276c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
2286c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			"(not in pool %p)\n", evt, pool->events);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_inc_return(&evt->free) != 1) {
2326c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(evt->hostdata->dev, "Freeing event_struct %p "
2336c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			"which is not in use!\n", evt);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_evt_struct: - Gets the next free event in pool
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the events to be searched
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the next event in "free" state, and NULL if none are free.
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that no synchronization is done here, we assume the host_lock
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will syncrhonze things.
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct srp_event_struct *get_event_struct(struct event_pool *pool)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int poolsize = pool->size;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int offset = pool->next;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < poolsize; i++) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = (offset + 1) % poolsize;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_dec_if_positive(&pool->events[offset].free)) {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pool->next = offset;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return &pool->events[offset];
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * init_event_struct: Initialize fields in an event struct that are always
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                    required.
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:        The event
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @done:       Routine to call when the event is responded to
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @format:     SRP or MAD format
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @timeout:    timeout value set in the CRQ
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_event_struct(struct srp_event_struct *evt_struct,
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      void (*done) (struct srp_event_struct *),
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 format,
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      int timeout)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->cmnd = NULL;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->cmnd_done = NULL;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->sync_srp = NULL;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->crq.format = format;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->crq.timeout = timeout;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->done = done;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for receiving SCSI responses from the hosting partition
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set_srp_direction: Set the fields in the srp related to data
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     direction and number of buffers based on the direction in
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     the scsi_cmnd and the number of buffers
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_srp_direction(struct scsi_cmnd *cmd,
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct srp_cmd *srp_cmd,
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      int numbuf)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
298ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 fmt;
299ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (numbuf == 0)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
303ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (numbuf == 1)
304ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		fmt = SRP_DATA_DESC_DIRECT;
305ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	else {
306ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		fmt = SRP_DATA_DESC_INDIRECT;
307ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		numbuf = min(numbuf, MAX_INDIRECT_BUFS);
308ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cmd->sc_data_direction == DMA_TO_DEVICE)
310ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			srp_cmd->data_out_desc_cnt = numbuf;
311ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		else
312ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			srp_cmd->data_in_desc_cnt = numbuf;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
314ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
315ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (cmd->sc_data_direction == DMA_TO_DEVICE)
316ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		srp_cmd->buf_fmt = fmt << 4;
317ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	else
318ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		srp_cmd->buf_fmt = fmt;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	srp_cmd whose additional_data member will be unmapped
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	device for which the memory is mapped
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
3274dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomleystatic void unmap_cmd_data(struct srp_cmd *cmd,
3284dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			   struct srp_event_struct *evt_struct,
3294dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			   struct device *dev)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
331ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 out_fmt, in_fmt;
332ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
333ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	out_fmt = cmd->buf_fmt >> 4;
334ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	in_fmt = cmd->buf_fmt & ((1U << 4) - 1);
335ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
336ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3384dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
339a71fa1fc43a29133f13ae6ada1a389ca298c0934FUJITA Tomonori	if (evt_struct->cmnd)
340a71fa1fc43a29133f13ae6ada1a389ca298c0934FUJITA Tomonori		scsi_dma_unmap(evt_struct->cmnd);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3439413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonoristatic int map_sg_list(struct scsi_cmnd *cmd, int nseg,
344ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		       struct srp_direct_buf *md)
3454dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley{
3464dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	int i;
3479413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	struct scatterlist *sg;
3484dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	u64 total_length = 0;
3494dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
3509413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	scsi_for_each_sg(cmd, sg, nseg, i) {
351ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		struct srp_direct_buf *descr = md + i;
3529413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		descr->va = sg_dma_address(sg);
3539413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		descr->len = sg_dma_len(sg);
354ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		descr->key = 0;
3559413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		total_length += sg_dma_len(sg);
3564dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley 	}
3574dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	return total_length;
3584dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley}
3594dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	Scsi_Cmnd with the scatterlist
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @srp_cmd:	srp_cmd that contains the memory descriptor
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	device for which to map dma memory
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 on success.
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int map_sg_data(struct scsi_cmnd *cmd,
3704dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		       struct srp_event_struct *evt_struct,
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       struct srp_cmd *srp_cmd, struct device *dev)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3744dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	int sg_mapped;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 total_length = 0;
376ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_direct_buf *data =
377ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		(struct srp_direct_buf *) srp_cmd->add_data;
378ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_indirect_buf *indirect =
379ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		(struct srp_indirect_buf *) data;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3819413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	sg_mapped = scsi_dma_map(cmd);
3829413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	if (!sg_mapped)
3839413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		return 1;
3849413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	else if (sg_mapped < 0)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_srp_direction(cmd, srp_cmd, sg_mapped);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* special case; we can use a single direct descriptor */
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_mapped == 1) {
3919413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		map_sg_list(cmd, sg_mapped, data);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
395ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.va = 0;
396ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
397ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.key = 0;
3984dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
3994dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (sg_mapped <= MAX_INDIRECT_BUFS) {
4009413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		total_length = map_sg_list(cmd, sg_mapped,
401ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   &indirect->desc_list[0]);
402ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		indirect->len = total_length;
4034dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		return 1;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4064dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	/* get indirect table */
4074dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (!evt_struct->ext_list) {
408ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		evt_struct->ext_list = (struct srp_direct_buf *)
4099413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			dma_alloc_coherent(dev,
410ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   SG_ALL * sizeof(struct srp_direct_buf),
411ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   &evt_struct->ext_list_token, 0);
4124dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		if (!evt_struct->ext_list) {
4137912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			if (!firmware_has_feature(FW_FEATURE_CMO))
4147912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				sdev_printk(KERN_ERR, cmd->device,
4157912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				            "Can't allocate memory "
4167912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				            "for indirect table\n");
417e637d553199e264327714da437e6c808f2f4b096Robert Jennings			scsi_dma_unmap(cmd);
4184dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			return 0;
4194dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		}
4204dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	}
4214dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
4229413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
4234dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
424ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->len = total_length;
425ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.va = evt_struct->ext_list_token;
426ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
427ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	memcpy(indirect->desc_list, evt_struct->ext_list,
428ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	       MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
4294dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley 	return 1;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	struct scsi_cmnd with the memory to be mapped
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @srp_cmd:	srp_cmd that contains the memory descriptor
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	dma device for which to map dma memory
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 on success.
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
4424dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				struct srp_event_struct *evt_struct,
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct srp_cmd *srp_cmd, struct device *dev)
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd->sc_data_direction) {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_FROM_DEVICE:
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_TO_DEVICE:
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_NONE:
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_BIDIRECTIONAL:
4526c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
4536c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "Can't map DMA_BIDIRECTIONAL to read/write\n");
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4566c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
4576c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "Unknown data direction 0x%02x; can't map!\n",
4586c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    cmd->sc_data_direction);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4629413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	return map_sg_data(cmd, evt_struct, srp_cmd, dev);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4653d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
4663d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * purge_requests: Our virtual adapter just shut down.  purge any sent requests
4673d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @hostdata:    the adapter
4683d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King */
4693d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
4703d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
4711117ef8aed95521f46dae3052c7120baae48c2bbBrian King	struct srp_event_struct *evt;
4723d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	unsigned long flags;
4733d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
4743d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
4751117ef8aed95521f46dae3052c7120baae48c2bbBrian King	while (!list_empty(&hostdata->sent)) {
4761117ef8aed95521f46dae3052c7120baae48c2bbBrian King		evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
4771117ef8aed95521f46dae3052c7120baae48c2bbBrian King		list_del(&evt->list);
4781117ef8aed95521f46dae3052c7120baae48c2bbBrian King		del_timer(&evt->timer);
4791117ef8aed95521f46dae3052c7120baae48c2bbBrian King
4801117ef8aed95521f46dae3052c7120baae48c2bbBrian King		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
4811117ef8aed95521f46dae3052c7120baae48c2bbBrian King		if (evt->cmnd) {
4821117ef8aed95521f46dae3052c7120baae48c2bbBrian King			evt->cmnd->result = (error_code << 16);
4831117ef8aed95521f46dae3052c7120baae48c2bbBrian King			unmap_cmd_data(&evt->iu.srp.cmd, evt,
4841117ef8aed95521f46dae3052c7120baae48c2bbBrian King				       evt->hostdata->dev);
4851117ef8aed95521f46dae3052c7120baae48c2bbBrian King			if (evt->cmnd_done)
4861117ef8aed95521f46dae3052c7120baae48c2bbBrian King				evt->cmnd_done(evt->cmnd);
4871117ef8aed95521f46dae3052c7120baae48c2bbBrian King		} else if (evt->done)
4881117ef8aed95521f46dae3052c7120baae48c2bbBrian King			evt->done(evt);
4891117ef8aed95521f46dae3052c7120baae48c2bbBrian King		free_event_struct(&evt->hostdata->pool, evt);
4901117ef8aed95521f46dae3052c7120baae48c2bbBrian King		spin_lock_irqsave(hostdata->host->host_lock, flags);
4913d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	}
4923d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
4933d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
4943d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
4953d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
4963d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_reset_host - Reset the connection to the server
4973d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @hostdata:	struct ibmvscsi_host_data to reset
4983d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
4993d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
5003d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
5013d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	scsi_block_requests(hostdata->host);
5023d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	atomic_set(&hostdata->request_limit, 0);
5033d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5043d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	purge_requests(hostdata, DID_ERROR);
5050f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	hostdata->reset_crq = 1;
5060f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	wake_up(&hostdata->work_wait_q);
5073d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
5083d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5093d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
5103d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_timeout - Internal command timeout handler
5113d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @evt_struct:	struct srp_event_struct that timed out
5123d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King *
5133d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * Called when an internally generated command times out
5143d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
5153d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
5163d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
5173d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
5183d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5193d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
5203d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->iu.srp.cmd.opcode);
5213d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5223d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	ibmvscsi_reset_host(hostdata);
5233d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
5243d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5253d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for sending and receiving SRPs
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	evt_struct to be sent
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
5333d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @timeout:	timeout in seconds - 0 means do not time command
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that this routine assumes that host_lock is held for synchronization
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
5393d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King				   struct ibmvscsi_host_data *hostdata,
5403d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King				   unsigned long timeout)
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
5433c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings	int request_status = 0;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
545f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King	int srp_req = 0;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
547a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	/* If we have exhausted our request limit, just fail this request,
548a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	 * unless it is for a reset or abort.
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note that there are rare cases involving driver generated requests
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (such as task management requests) that the mid layer may think we
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can handle more requests (can_queue) when we actually can't
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
553cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
554f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King		srp_req = 1;
555cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		request_status =
556cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher			atomic_dec_if_positive(&hostdata->request_limit);
557cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		/* If request limit was -1 when we started, it is now even
558cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		 * less than that
559cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		 */
560cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		if (request_status < -1)
561cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher			goto send_error;
562a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		/* Otherwise, we may have run out of requests. */
5633c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		/* If request limit was 0 when we started the adapter is in the
5643c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 * process of performing a login with the server adapter, or
5653c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 * we may have run out of requests.
5663c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 */
5673c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		else if (request_status == -1 &&
5683c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		         evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
5693c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings			goto send_busy;
570a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		/* Abort and reset calls should make it through.
571a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 * Nothing except abort and reset should use the last two
572a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 * slots unless we had two or less to begin with.
573a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 */
574a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		else if (request_status < 2 &&
575a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		         evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
576a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			/* In the case that we have less than two requests
577a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * available, check the server limit as a combination
578a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * of the request limit and the number of requests
579a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * in-flight (the size of the send list).  If the
580a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * server limit is greater than 2, return busy so
581a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * that the last two are reserved for reset and abort.
582a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 */
583a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			int server_limit = request_status;
584a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			struct srp_event_struct *tmp_evt;
585a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings
586a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			list_for_each_entry(tmp_evt, &hostdata->sent, list) {
587a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings				server_limit++;
588a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			}
589a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings
590a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			if (server_limit > 2)
591a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings				goto send_busy;
592a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		}
593cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy the IU into the transfer area */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*evt_struct->xfer_iu = evt_struct->iu;
597ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add this to the sent list.  We need to do this
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * before we actually send
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in case it comes back REALLY fast
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&evt_struct->list, &hostdata->sent);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6053d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	init_timer(&evt_struct->timer);
6063d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	if (timeout) {
6073d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.data = (unsigned long) evt_struct;
6083d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.expires = jiffies + (timeout * HZ);
6093d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
6103d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		add_timer(&evt_struct->timer);
6113d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	}
6123d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc =
614d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	     ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del(&evt_struct->list);
6163d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		del_timer(&evt_struct->timer);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
618860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
619860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * Firmware will send a CRQ with a transport event (0xFF) to
620860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * tell this client what has happened to the transport.  This
621860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * will be handled in ibmvscsi_handle_crq()
622860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 */
623860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rc == H_CLOSED) {
624860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			dev_warn(hostdata->dev, "send warning. "
625860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			         "Receive queue closed, will retry.\n");
626860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			goto send_busy;
627860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
6286c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "send error %d\n", rc);
629f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King		if (srp_req)
630f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King			atomic_inc(&hostdata->request_limit);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send_error;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
636cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher send_busy:
6374dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&hostdata->pool, evt_struct);
640f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King	if (srp_req && request_status != -1)
6413c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		atomic_inc(&hostdata->request_limit);
642a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	return SCSI_MLQUEUE_HOST_BUSY;
643cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
644cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher send_error:
645cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
646cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
647cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (evt_struct->cmnd != NULL) {
648cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->cmnd->result = DID_ERROR << 16;
649cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->cmnd_done(evt_struct->cmnd);
650cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	} else if (evt_struct->done)
651cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->done(evt_struct);
652cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
653cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	free_event_struct(&hostdata->pool, evt_struct);
654cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	return 0;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_cmd_rsp: -  Handle responses from commands
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	srp_event_struct to be handled
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used as a callback by when sending scsi cmds.
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gets called by ibmvscsi_handle_crq()
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_cmd_rsp(struct srp_event_struct *evt_struct)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *cmnd = evt_struct->cmnd;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
669ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(rsp->opcode != SRP_RSP)) {
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
6716c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_warn(evt_struct->hostdata->dev,
6726c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				 "bad SRP RSP type %d\n", rsp->opcode);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmnd) {
676c3a3b55ae80a0d595445064159c69f8e80911e85Brian King		cmnd->result |= rsp->status;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(cmnd->sense_buffer,
679ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			       rsp->data,
680ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			       rsp->sense_data_len);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unmap_cmd_data(&evt_struct->iu.srp.cmd,
6824dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			       evt_struct,
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       evt_struct->hostdata->dev);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
685ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		if (rsp->flags & SRP_RSP_FLAG_DOOVER)
6869413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			scsi_set_resid(cmnd, rsp->data_out_res_cnt);
687ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
6889413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			scsi_set_resid(cmnd, rsp->data_in_res_cnt);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->cmnd_done)
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt_struct->cmnd_done(cmnd);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lun_from_dev: - Returns the lun of the scsi device
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	struct scsi_device
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 lun_from_dev(struct scsi_device *dev)
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_queue: - The queuecommand function of the scsi template
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	struct scsi_cmnd to be executed
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @done:	Callback function to be called when cmd is completed
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
710f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 void (*done) (struct scsi_cmnd *))
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_cmd *srp_cmd;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
715ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_indirect_buf *indirect;
7167603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmnd->device);
718ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 out_fmt, in_fmt;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
720c3a3b55ae80a0d595445064159c69f8e80911e85Brian King	cmnd->result = (DID_OK << 16);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!evt_struct)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SCSI_MLQUEUE_HOST_BUSY;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up the actual SRP IU */
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	srp_cmd = &evt_struct->iu.srp.cmd;
727ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
728ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	srp_cmd->opcode = SRP_CMD;
72964a87b244b9297667ca80264aab849a36f494884Boaz Harrosh	memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	srp_cmd->lun = ((u64) lun) << 48;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7324dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
7337912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings		if (!firmware_has_feature(FW_FEATURE_CMO))
7347912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			sdev_printk(KERN_ERR, cmnd->device,
7357912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			            "couldn't convert cmd to srp_cmd\n");
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_event_struct(&hostdata->pool, evt_struct);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SCSI_MLQUEUE_HOST_BUSY;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7404dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	init_event_struct(evt_struct,
7414dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			  handle_cmd_rsp,
7424dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			  VIOSRP_SRP_FORMAT,
743242f9dcb8ba6f68fcd217a119a7648a4f69290e9Jens Axboe			  cmnd->request->timeout/HZ);
7444dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
7454dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	evt_struct->cmnd = cmnd;
7464dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	evt_struct->cmnd_done = done;
7474dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fix up dma address of the buffer itself */
749ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect = (struct srp_indirect_buf *) srp_cmd->add_data;
750ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	out_fmt = srp_cmd->buf_fmt >> 4;
751ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1);
752ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
753ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	     out_fmt == SRP_DATA_DESC_INDIRECT) &&
754ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	    indirect->table_desc.va == 0) {
755ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		indirect->table_desc.va = evt_struct->crq.IU_data_ptr +
756ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			offsetof(struct srp_cmd, add_data) +
757ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			offsetof(struct srp_indirect_buf, desc_list);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7603d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
763f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic DEF_SCSI_QCMD(ibmvscsi_queuecommand)
764f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzik
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for driver initialization
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7683507e13fcba6b97501891a410ec8ef9f1f188620Brian King
7693507e13fcba6b97501891a410ec8ef9f1f188620Brian King/**
770126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * map_persist_bufs: - Pre-map persistent data for adapter logins
771126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:   ibmvscsi_host_data of host
772126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
773126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
774126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Return 1 on error, 0 on success.
775126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
776126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
777126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
778126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
779126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
780126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King					     sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
781126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
782126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
783126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
784126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 1;
785126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
786126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
787126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
788126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     &hostdata->madapter_info,
789126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     sizeof(hostdata->madapter_info),
790126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     DMA_BIDIRECTIONAL);
791126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
792126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
793126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dma_unmap_single(hostdata->dev, hostdata->caps_addr,
794126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
795126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 1;
796126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
797126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
798126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return 0;
799126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
800126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
801126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
802126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
803126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:   ibmvscsi_host_data of host
804126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
805126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Unmap the capabilities and adapter info DMA buffers
806126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
807126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
808126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
809126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	dma_unmap_single(hostdata->dev, hostdata->caps_addr,
810126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
811126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
812126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
813126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			 sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
814126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
815126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
816126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
8173507e13fcba6b97501891a410ec8ef9f1f188620Brian King * login_rsp: - Handle response to SRP login request
8183507e13fcba6b97501891a410ec8ef9f1f188620Brian King * @evt_struct:	srp_event_struct with the response
8193507e13fcba6b97501891a410ec8ef9f1f188620Brian King *
8203507e13fcba6b97501891a410ec8ef9f1f188620Brian King * Used as a "done" callback by when sending srp_login. Gets called
8213507e13fcba6b97501891a410ec8ef9f1f188620Brian King * by ibmvscsi_handle_crq()
8223507e13fcba6b97501891a410ec8ef9f1f188620Brian King*/
8233507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic void login_rsp(struct srp_event_struct *evt_struct)
8243507e13fcba6b97501891a410ec8ef9f1f188620Brian King{
8253507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
8263507e13fcba6b97501891a410ec8ef9f1f188620Brian King	switch (evt_struct->xfer_iu->srp.login_rsp.opcode) {
8273507e13fcba6b97501891a410ec8ef9f1f188620Brian King	case SRP_LOGIN_RSP:	/* it worked! */
8283507e13fcba6b97501891a410ec8ef9f1f188620Brian King		break;
8293507e13fcba6b97501891a410ec8ef9f1f188620Brian King	case SRP_LOGIN_REJ:	/* refused! */
8303507e13fcba6b97501891a410ec8ef9f1f188620Brian King		dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
8313507e13fcba6b97501891a410ec8ef9f1f188620Brian King			 evt_struct->xfer_iu->srp.login_rej.reason);
8323507e13fcba6b97501891a410ec8ef9f1f188620Brian King		/* Login failed.  */
8333507e13fcba6b97501891a410ec8ef9f1f188620Brian King		atomic_set(&hostdata->request_limit, -1);
8343507e13fcba6b97501891a410ec8ef9f1f188620Brian King		return;
8353507e13fcba6b97501891a410ec8ef9f1f188620Brian King	default:
8363507e13fcba6b97501891a410ec8ef9f1f188620Brian King		dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
8373507e13fcba6b97501891a410ec8ef9f1f188620Brian King			evt_struct->xfer_iu->srp.login_rsp.opcode);
8383507e13fcba6b97501891a410ec8ef9f1f188620Brian King		/* Login failed.  */
8393507e13fcba6b97501891a410ec8ef9f1f188620Brian King		atomic_set(&hostdata->request_limit, -1);
8403507e13fcba6b97501891a410ec8ef9f1f188620Brian King		return;
8413507e13fcba6b97501891a410ec8ef9f1f188620Brian King	}
8423507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8433507e13fcba6b97501891a410ec8ef9f1f188620Brian King	dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
844126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->client_migrated = 0;
8453507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8463507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* Now we know what the real request-limit is.
8473507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * This value is set rather than added to request_limit because
8483507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * request_limit could have been set to -1 by this client.
8493507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 */
8503507e13fcba6b97501891a410ec8ef9f1f188620Brian King	atomic_set(&hostdata->request_limit,
8513507e13fcba6b97501891a410ec8ef9f1f188620Brian King		   evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
8523507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8533507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* If we had any pending I/Os, kick them */
8543507e13fcba6b97501891a410ec8ef9f1f188620Brian King	scsi_unblock_requests(hostdata->host);
8553507e13fcba6b97501891a410ec8ef9f1f188620Brian King}
8563507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8573507e13fcba6b97501891a410ec8ef9f1f188620Brian King/**
8583507e13fcba6b97501891a410ec8ef9f1f188620Brian King * send_srp_login: - Sends the srp login
8593507e13fcba6b97501891a410ec8ef9f1f188620Brian King * @hostdata:	ibmvscsi_host_data of host
8603507e13fcba6b97501891a410ec8ef9f1f188620Brian King *
8613507e13fcba6b97501891a410ec8ef9f1f188620Brian King * Returns zero if successful.
8623507e13fcba6b97501891a410ec8ef9f1f188620Brian King*/
8633507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic int send_srp_login(struct ibmvscsi_host_data *hostdata)
8643507e13fcba6b97501891a410ec8ef9f1f188620Brian King{
8653507e13fcba6b97501891a410ec8ef9f1f188620Brian King	int rc;
8663507e13fcba6b97501891a410ec8ef9f1f188620Brian King	unsigned long flags;
8673507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct srp_login_req *login;
8683507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
8693507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8703507e13fcba6b97501891a410ec8ef9f1f188620Brian King	BUG_ON(!evt_struct);
8713507e13fcba6b97501891a410ec8ef9f1f188620Brian King	init_event_struct(evt_struct, login_rsp,
8723507e13fcba6b97501891a410ec8ef9f1f188620Brian King			  VIOSRP_SRP_FORMAT, login_timeout);
8733507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8743507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login = &evt_struct->iu.srp.login_req;
8753507e13fcba6b97501891a410ec8ef9f1f188620Brian King	memset(login, 0, sizeof(*login));
8763507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->opcode = SRP_LOGIN_REQ;
8773507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->req_it_iu_len = sizeof(union srp_iu);
8783507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
8793507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8803507e13fcba6b97501891a410ec8ef9f1f188620Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
8813507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* Start out with a request limit of 0, since this is negotiated in
8823507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * the login request we are just sending and login requests always
8833507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * get sent by the driver regardless of request_limit.
8843507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 */
8853507e13fcba6b97501891a410ec8ef9f1f188620Brian King	atomic_set(&hostdata->request_limit, 0);
8863507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8873507e13fcba6b97501891a410ec8ef9f1f188620Brian King	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
8883507e13fcba6b97501891a410ec8ef9f1f188620Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
8893507e13fcba6b97501891a410ec8ef9f1f188620Brian King	dev_info(hostdata->dev, "sent SRP login\n");
8903507e13fcba6b97501891a410ec8ef9f1f188620Brian King	return rc;
8913507e13fcba6b97501891a410ec8ef9f1f188620Brian King};
8923507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
894126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * capabilities_rsp: - Handle response to MAD adapter capabilities request
895126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @evt_struct:	srp_event_struct with the response
896126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
897126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Used as a "done" callback by when sending adapter_info.
898126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
899126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void capabilities_rsp(struct srp_event_struct *evt_struct)
900126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
901126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
902126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
903126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (evt_struct->xfer_iu->mad.capabilities.common.status) {
904126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
905126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			evt_struct->xfer_iu->mad.capabilities.common.status);
906126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	} else {
907126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP)
908126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			dev_info(hostdata->dev, "Partition migration not supported\n");
909126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
910126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		if (client_reserve) {
911126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			if (hostdata->caps.reserve.common.server_support ==
912126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			    SERVER_SUPPORTS_CAP)
913126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				dev_info(hostdata->dev, "Client reserve enabled\n");
914126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			else
915126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				dev_info(hostdata->dev, "Client reserve not supported\n");
916126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		}
917126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
918126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
919126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	send_srp_login(hostdata);
920126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
921126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
922126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
923126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * send_mad_capabilities: - Sends the mad capabilities request
924126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *      and stores the result so it can be retrieved with
925126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:	ibmvscsi_host_data of host
926126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
927126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
928126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
929126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct viosrp_capabilities *req;
930126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct srp_event_struct *evt_struct;
931126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unsigned long flags;
93261c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	struct device_node *of_node = hostdata->dev->of_node;
933126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	const char *location;
934126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
935126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	evt_struct = get_event_struct(&hostdata->pool);
936126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	BUG_ON(!evt_struct);
937126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
938126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	init_event_struct(evt_struct, capabilities_rsp,
939126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			  VIOSRP_MAD_FORMAT, info_timeout);
940126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
941126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req = &evt_struct->iu.mad.capabilities;
942126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	memset(req, 0, sizeof(*req));
943126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
944126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.flags = CAP_LIST_SUPPORTED;
945126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (hostdata->client_migrated)
946126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.flags |= CLIENT_MIGRATED;
947126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
948126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
949126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		sizeof(hostdata->caps.name));
950126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0';
951126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
952126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	location = of_get_property(of_node, "ibm,loc-code", NULL);
953126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	location = location ? location : dev_name(hostdata->dev);
954126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
955126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0';
956126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
957126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->common.type = VIOSRP_CAPABILITIES_TYPE;
958126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->buffer = hostdata->caps_addr;
959126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
960126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES;
961126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration);
962126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP;
963126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.ecl = 1;
964126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
965126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (client_reserve) {
966126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES;
967126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve);
968126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP;
969126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2;
970126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		req->common.length = sizeof(hostdata->caps);
971126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	} else
972126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve);
973126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
974126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
975126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
976126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
977126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
978126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
979126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
980126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
981c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * fast_fail_rsp: - Handle response to MAD enable fast fail
982c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * @evt_struct:	srp_event_struct with the response
983c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings *
984c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * Used as a "done" callback by when sending enable fast fail. Gets called
985c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * by ibmvscsi_handle_crq()
986c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings */
987c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic void fast_fail_rsp(struct srp_event_struct *evt_struct)
988c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings{
989c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
990c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status;
991c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
992c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	if (status == VIOSRP_MAD_NOT_SUPPORTED)
993c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "fast_fail not supported in server\n");
994c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	else if (status == VIOSRP_MAD_FAILED)
995c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "fast_fail request failed\n");
996c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	else if (status != VIOSRP_MAD_SUCCESS)
997c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
998c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
999126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	send_mad_capabilities(hostdata);
1000c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings}
1001c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1002c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings/**
1003c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * init_host - Start host initialization
1004c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * @hostdata:	ibmvscsi_host_data of host
1005c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings *
1006c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * Returns zero if successful.
1007c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings */
1008c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
1009c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings{
1010c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	int rc;
1011c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	unsigned long flags;
1012c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct viosrp_fast_fail *fast_fail_mad;
1013c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct srp_event_struct *evt_struct;
1014c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1015126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (!fast_fail) {
1016126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		send_mad_capabilities(hostdata);
1017126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 0;
1018126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
1019c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1020c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	evt_struct = get_event_struct(&hostdata->pool);
1021c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	BUG_ON(!evt_struct);
1022c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1023c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
1024c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1025c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad = &evt_struct->iu.mad.fast_fail;
1026c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
1027c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL;
1028c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad->common.length = sizeof(*fast_fail_mad);
1029c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1030c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	spin_lock_irqsave(hostdata->host->host_lock, flags);
1031c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
1032c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1033c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	return rc;
1034c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings}
1035c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1036c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings/**
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter_info_rsp: - Handle response to MAD adapter info request
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	srp_event_struct with the response
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used as a "done" callback by when sending adapter_info. Gets called
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by ibmvscsi_handle_crq()
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adapter_info_rsp(struct srp_event_struct *evt_struct)
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
10486c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "error %d getting adapter info\n",
10496c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			evt_struct->xfer_iu->mad.adapter_info.common.status);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10516c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_info(hostdata->dev, "host srp version: %s, "
10526c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 "host partition %s (%d), OS %d, max io %u\n",
10536c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.srp_version,
10546c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.partition_name,
10556c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.partition_number,
10566c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.os_type,
10576c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.port_max_txu[0]);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (hostdata->madapter_info.port_max_txu[0])
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hostdata->host->max_sectors =
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hostdata->madapter_info.port_max_txu[0] >> 9;
1062154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher
1063154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		if (hostdata->madapter_info.os_type == 3 &&
1064154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
10656c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
10666c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				hostdata->madapter_info.srp_version);
10676c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
10686c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				MAX_INDIRECT_BUFS);
1069154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
1070154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		}
1071e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King
1072e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King		if (hostdata->madapter_info.os_type == 3) {
1073e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King			enable_fast_fail(hostdata);
1074e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King			return;
1075e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King		}
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10773507e13fcba6b97501891a410ec8ef9f1f188620Brian King
1078e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King	send_srp_login(hostdata);
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send_mad_adapter_info: - Sends the mad adapter info request
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      and stores the result so it can be retrieved with
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      sysfs.  We COULD consider causing a failure if the
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      returned SRP version doesn't match ours.
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero if successful.
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct viosrp_adapter_info *req;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
109406f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	unsigned long flags;
1095e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
10973507e13fcba6b97501891a410ec8ef9f1f188620Brian King	BUG_ON(!evt_struct);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_event_struct(evt_struct,
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  adapter_info_rsp,
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  VIOSRP_MAD_FORMAT,
1102e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings			  info_timeout);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = &evt_struct->iu.mad.adapter_info;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(req, 0x00, sizeof(*req));
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req->common.length = sizeof(hostdata->madapter_info);
1109126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->buffer = hostdata->adapter_info_addr;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111106f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
1112126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
11136c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
111406f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11183507e13fcba6b97501891a410ec8ef9f1f188620Brian King * init_adapter: Start virtual adapter initialization sequence
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11203507e13fcba6b97501891a410ec8ef9f1f188620Brian King */
11213507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic void init_adapter(struct ibmvscsi_host_data *hostdata)
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_mad_adapter_info(hostdata);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sync_completion: Signal that a synchronous command has completed
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that after returning from this call, the evt_struct is freed.
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the caller waiting on this completion shouldn't touch the evt_struct
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * again.
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sync_completion(struct srp_event_struct *evt_struct)
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy the response back */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->sync_srp)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*evt_struct->sync_srp = *evt_struct->xfer_iu;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	complete(&evt_struct->comp);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_abort: Abort a command...from scsi host template
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send this over to the server and wait synchronously for the response
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11477603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_tsk_mgmt *tsk_mgmt;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *tmp_evt, *found_evt;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union viosrp_iu srp_rsp;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rsp_rc;
1153be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	unsigned long flags;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmd->device);
1155860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	unsigned long wait_switch = 0;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First, find this command in our sent list so we can figure
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * out the correct tag
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1160be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
1161860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	wait_switch = jiffies + (init_timeout * HZ);
1162860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	do {
1163860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		found_evt = NULL;
1164860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
1165860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			if (tmp_evt->cmnd == cmd) {
1166860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				found_evt = tmp_evt;
1167860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				break;
1168860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			}
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (!found_evt) {
1172860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1173860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return SUCCESS;
1174860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1176860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt = get_event_struct(&hostdata->pool);
1177860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (evt == NULL) {
1178860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1179860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			sdev_printk(KERN_ERR, cmd->device,
1180860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				"failed to allocate abort event\n");
1181860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return FAILED;
1182860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1184860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_event_struct(evt,
1185860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  sync_completion,
1186860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  VIOSRP_SRP_FORMAT,
1187e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings				  abort_timeout);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1189860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* Set up an abort SRP command */
1192860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
1193860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->opcode = SRP_TSK_MGMT;
1194860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->lun = ((u64) lun) << 48;
1195860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
1196860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->task_tag = (u64) found_evt;
1197860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1198860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt->sync_srp = &srp_rsp;
1199860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1200860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_completion(&evt->comp);
1201e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
1202860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1203860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
1204860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			break;
1205860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1206860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1207860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		msleep(10);
1208860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_lock_irqsave(hostdata->host->host_lock, flags);
1209860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	} while (time_before(jiffies, wait_switch));
1210860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1211be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1212860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1213be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	if (rsp_rc != 0) {
12146c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
12156c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "failed to send abort() event. rc=%d\n", rsp_rc);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1219860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	sdev_printk(KERN_INFO, cmd->device,
1220fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar                    "aborting command. lun 0x%llx, tag 0x%llx\n",
1221860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		    (((u64) lun) << 48), (u64) found_evt);
1222860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_for_completion(&evt->comp);
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure we got a good response */
1226ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
12286c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
12296c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    srp_rsp.srp.rsp.opcode);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1233ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
1234ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rsp_rc = srp_rsp.srp.rsp.status;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rsp_rc) {
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
12406c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device,
1241fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar				    "abort code %d for task tag 0x%llx\n",
12426c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    rsp_rc, tsk_mgmt->task_tag);
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Because we dropped the spinlock above, it's possible
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The event is no longer in our list.  Make sure it didn't
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * complete while we were aborting
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1250be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found_evt = NULL;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp_evt->cmnd == cmd) {
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found_evt = tmp_evt;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (found_evt == NULL) {
1260be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1261fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar		sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
12626c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    tsk_mgmt->task_tag);
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SUCCESS;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1266fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
12676c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		    tsk_mgmt->task_tag);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->result = (DID_ABORT << 16);
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&found_evt->list);
12714dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
12724dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		       found_evt->hostdata->dev);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&found_evt->hostdata->pool, found_evt);
1274be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&hostdata->request_limit);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * template send this over to the server and wait synchronously for the
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * response
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12867603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_tsk_mgmt *tsk_mgmt;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *tmp_evt, *pos;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union viosrp_iu srp_rsp;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rsp_rc;
1292be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	unsigned long flags;
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmd->device);
1294860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	unsigned long wait_switch = 0;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1296be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
1297860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	wait_switch = jiffies + (init_timeout * HZ);
1298860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	do {
1299860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt = get_event_struct(&hostdata->pool);
1300860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (evt == NULL) {
1301860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1302860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			sdev_printk(KERN_ERR, cmd->device,
1303860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				"failed to allocate reset event\n");
1304860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return FAILED;
1305860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1307860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_event_struct(evt,
1308860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  sync_completion,
1309860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  VIOSRP_SRP_FORMAT,
1310e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings				  reset_timeout);
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1312860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1314860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* Set up a lun reset SRP command */
1315860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
1316860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->opcode = SRP_TSK_MGMT;
1317860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->lun = ((u64) lun) << 48;
1318860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1320860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt->sync_srp = &srp_rsp;
1321860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1322860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_completion(&evt->comp);
1323e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
1324860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1325860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
1326860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			break;
1327860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1328860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1329860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		msleep(10);
1330860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_lock_irqsave(hostdata->host->host_lock, flags);
1331860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	} while (time_before(jiffies, wait_switch));
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1333be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1334860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1335be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	if (rsp_rc != 0) {
13366c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
13376c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "failed to send reset event. rc=%d\n", rsp_rc);
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
1342860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		    (((u64) lun) << 48));
1343860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_for_completion(&evt->comp);
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure we got a good response */
1347ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
13496c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
13506c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    srp_rsp.srp.rsp.opcode);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1354ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
1355ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rsp_rc = srp_rsp.srp.rsp.status;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rsp_rc) {
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
13616c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device,
1362fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar				    "reset code %d for task tag 0x%llx\n",
13636c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    rsp_rc, tsk_mgmt->task_tag);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We need to find all commands for this LUN that have not yet been
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * responded to, and fail them with DID_RESET
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1370be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_evt->cmnd)
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->cmnd->result = (DID_RESET << 16);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del(&tmp_evt->list);
13764dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
13774dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				       tmp_evt->hostdata->dev);
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_event_struct(&tmp_evt->hostdata->pool,
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   tmp_evt);
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			atomic_inc(&hostdata->request_limit);
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_evt->cmnd_done)
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->cmnd_done(tmp_evt->cmnd);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (tmp_evt->done)
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->done(tmp_evt);
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1387be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13923d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
13933d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @cmd:	struct scsi_cmnd having problems
13943d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
13953d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13973d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	unsigned long wait_switch = 0;
13987603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14003d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
14013d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14023d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	ibmvscsi_reset_host(hostdata);
14033d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14043d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	for (wait_switch = jiffies + (init_timeout * HZ);
14053d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	     time_before(jiffies, wait_switch) &&
14063d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		     atomic_read(&hostdata->request_limit) < 2;) {
14073d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14083d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		msleep(10);
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14103d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14113d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	if (atomic_read(&hostdata->request_limit) <= 0)
14123d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		return FAILED;
14133d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14143d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	return SUCCESS;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @crq:	Command/Response queue
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ibmvscsi_handle_crq(struct viosrp_crq *crq,
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct ibmvscsi_host_data *hostdata)
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14266c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King	long rc;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct =
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (struct srp_event_struct *)crq->IU_data_ptr;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (crq->valid) {
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xC0:		/* initialization */
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (crq->format) {
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x01:	/* Initialization message */
14346c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "partner initialized\n");
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Send back a response */
1436d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse			if ((rc = ibmvscsi_ops->send_crq(hostdata,
1437d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse							 0xC002000000000000LL, 0)) == 0) {
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Now login */
14393507e13fcba6b97501891a410ec8ef9f1f188620Brian King				init_adapter(hostdata);
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
14416c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x02:	/* Initialization response */
14466c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "partner initialization complete\n");
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Now login */
14493507e13fcba6b97501891a410ec8ef9f1f188620Brian King			init_adapter(hostdata);
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
14526c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14552b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher	case 0xFF:	/* Hypervisor telling us the connection is closed */
14562b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		scsi_block_requests(hostdata->host);
1457cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		atomic_set(&hostdata->request_limit, 0);
14582b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		if (crq->format == 0x06) {
14592b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher			/* We need to re-setup the interpartition connection */
14606c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "Re-enabling adapter!\n");
1461126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			hostdata->client_migrated = 1;
14620f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			hostdata->reenable_crq = 1;
14632b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher			purge_requests(hostdata, DID_REQUEUE);
14640f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			wake_up(&hostdata->work_wait_q);
14652b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		} else {
14666c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
14676c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				crq->format);
14680f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			ibmvscsi_reset_host(hostdata);
14692b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x80:		/* real payload */
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
14746c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
14756c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			crq->valid);
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The only kind of payload CRQs we should get are responses to
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * things we send. Make sure this response is to something we
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * actually sent
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!valid_event_struct(&hostdata->pool, evt_struct)) {
14846c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (void *)crq->IU_data_ptr);
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&evt_struct->free)) {
14906c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
14916c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			(void *)crq->IU_data_ptr);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (crq->format == VIOSRP_SRP_FORMAT)
1496ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   &hostdata->request_limit);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14993d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	del_timer(&evt_struct->timer);
15003d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
1501ca61668b82a902143997794aae3f681a602e6ebcBrian King	if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
1502c3a3b55ae80a0d595445064159c69f8e80911e85Brian King		evt_struct->cmnd->result = DID_ERROR << 16;
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->done)
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt_struct->done(evt_struct);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
15066c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Lock the host_lock before messing with these structures, since we
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * are running in a task context
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&evt_struct->list);
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&evt_struct->hostdata->pool, evt_struct);
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_get_host_config: Send the command to the server to get host
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configuration data.  The data is opaque to us.
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned char *buffer, int length)
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct viosrp_host_config *host_config;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
152706f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	unsigned long flags;
1528e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	dma_addr_t addr;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!evt_struct) {
15336c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_event_struct(evt_struct,
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  sync_completion,
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  VIOSRP_MAD_FORMAT,
1540e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings			  info_timeout);
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config = &evt_struct->iu.mad.host_config;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up a lun reset SRP command */
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(host_config, 0x00, sizeof(*host_config));
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config->common.length = length;
1548e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	host_config->buffer = addr = dma_map_single(hostdata->dev, buffer,
1549e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori						    length,
1550e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori						    DMA_BIDIRECTIONAL);
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15528d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori	if (dma_mapping_error(hostdata->dev, host_config->buffer)) {
15537912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings		if (!firmware_has_feature(FW_FEATURE_CMO))
15547912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			dev_err(hostdata->dev,
15557912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			        "dma_mapping error getting host config\n");
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_event_struct(&hostdata->pool, evt_struct);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_completion(&evt_struct->comp);
156106f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
1562e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
156306f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1564e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	if (rc == 0)
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wait_for_completion(&evt_struct->comp);
1566e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15710979c84b4affaf924a894380dd0069638b64de03Robert Jennings/**
15720979c84b4affaf924a894380dd0069638b64de03Robert Jennings * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
15730979c84b4affaf924a894380dd0069638b64de03Robert Jennings * @sdev:	struct scsi_device device to configure
15740979c84b4affaf924a894380dd0069638b64de03Robert Jennings *
15750979c84b4affaf924a894380dd0069638b64de03Robert Jennings * Enable allow_restart for a device if it is a disk.  Adjust the
15760979c84b4affaf924a894380dd0069638b64de03Robert Jennings * queue_depth here also as is required by the documentation for
15770979c84b4affaf924a894380dd0069638b64de03Robert Jennings * struct scsi_host_template.
15780979c84b4affaf924a894380dd0069638b64de03Robert Jennings */
15790979c84b4affaf924a894380dd0069638b64de03Robert Jenningsstatic int ibmvscsi_slave_configure(struct scsi_device *sdev)
15800979c84b4affaf924a894380dd0069638b64de03Robert Jennings{
15810979c84b4affaf924a894380dd0069638b64de03Robert Jennings	struct Scsi_Host *shost = sdev->host;
15820979c84b4affaf924a894380dd0069638b64de03Robert Jennings	unsigned long lock_flags = 0;
15830979c84b4affaf924a894380dd0069638b64de03Robert Jennings
15840979c84b4affaf924a894380dd0069638b64de03Robert Jennings	spin_lock_irqsave(shost->host_lock, lock_flags);
1585d1a357fcc8348d325d151f6fe0ea54e317652457Brian King	if (sdev->type == TYPE_DISK) {
15860979c84b4affaf924a894380dd0069638b64de03Robert Jennings		sdev->allow_restart = 1;
1587e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
1588d1a357fcc8348d325d151f6fe0ea54e317652457Brian King	}
15890979c84b4affaf924a894380dd0069638b64de03Robert Jennings	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
15900979c84b4affaf924a894380dd0069638b64de03Robert Jennings	spin_unlock_irqrestore(shost->host_lock, lock_flags);
15910979c84b4affaf924a894380dd0069638b64de03Robert Jennings	return 0;
15920979c84b4affaf924a894380dd0069638b64de03Robert Jennings}
15930979c84b4affaf924a894380dd0069638b64de03Robert Jennings
1594742d25b819f11dce91b89e6c9ac17402a119f20aBrian King/**
1595742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * ibmvscsi_change_queue_depth - Change the device's queue depth
1596742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * @sdev:	scsi device struct
1597742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * @qdepth:	depth to set
1598e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie * @reason:	calling context
1599742d25b819f11dce91b89e6c9ac17402a119f20aBrian King *
1600742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * Return value:
1601742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * 	actual depth set
1602742d25b819f11dce91b89e6c9ac17402a119f20aBrian King **/
1603e881a172dac4d9ea3b2a1540041d872963c269bdMike Christiestatic int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth,
1604e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie				       int reason)
1605742d25b819f11dce91b89e6c9ac17402a119f20aBrian King{
1606e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie	if (reason != SCSI_QDEPTH_DEFAULT)
1607e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie		return -EOPNOTSUPP;
1608e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie
1609742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
1610742d25b819f11dce91b89e6c9ac17402a119f20aBrian King		qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
1611742d25b819f11dce91b89e6c9ac17402a119f20aBrian King
1612742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	scsi_adjust_queue_depth(sdev, 0, qdepth);
1613742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	return sdev->queue_depth;
1614742d25b819f11dce91b89e6c9ac17402a119f20aBrian King}
1615742d25b819f11dce91b89e6c9ac17402a119f20aBrian King
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sysfs attributes
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1619126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic ssize_t show_host_vhost_loc(struct device *dev,
1620126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				   struct device_attribute *attr, char *buf)
1621126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
1622126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct Scsi_Host *shost = class_to_shost(dev);
1623126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
1624126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	int len;
1625126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1626126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
1627126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		       hostdata->caps.loc);
1628126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return len;
1629126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
1630126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1631126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic struct device_attribute ibmvscsi_host_vhost_loc = {
1632126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.attr = {
1633126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .name = "vhost_loc",
1634126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .mode = S_IRUGO,
1635126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 },
1636126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.show = show_host_vhost_loc,
1637126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
1638126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1639126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic ssize_t show_host_vhost_name(struct device *dev,
1640126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				    struct device_attribute *attr, char *buf)
1641126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
1642126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct Scsi_Host *shost = class_to_shost(dev);
1643126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
1644126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	int len;
1645126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1646126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
1647126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		       hostdata->caps.name);
1648126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return len;
1649126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
1650126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1651126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic struct device_attribute ibmvscsi_host_vhost_name = {
1652126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.attr = {
1653126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .name = "vhost_name",
1654126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .mode = S_IRUGO,
1655126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 },
1656126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.show = show_host_vhost_name,
1657126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
1658126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1659ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_srp_version(struct device *dev,
1660ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				     struct device_attribute *attr, char *buf)
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1662ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
16637603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%s\n",
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.srp_version);
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_srp_version = {
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "srp_version",
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_srp_version,
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1679ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_partition_name(struct device *dev,
1680ee959b00c335d7780136c5abda37809191fe52c3Tony Jones					struct device_attribute *attr,
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					char *buf)
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1683ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
16847603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%s\n",
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.partition_name);
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1692ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_partition_name = {
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "partition_name",
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_partition_name,
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1700ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_partition_number(struct device *dev,
1701ee959b00c335d7780136c5abda37809191fe52c3Tony Jones					  struct device_attribute *attr,
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  char *buf)
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1704ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17057603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n",
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.partition_number);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1713ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_partition_number = {
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "partition_number",
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_partition_number,
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_mad_version(struct device *dev,
1722ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				     struct device_attribute *attr, char *buf)
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1724ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17257603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n",
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.mad_version);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1733ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_mad_version = {
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "mad_version",
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_mad_version,
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_os_type(struct device *dev,
1742ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				 struct device_attribute *attr, char *buf)
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1744ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17457603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1752ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_os_type = {
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "os_type",
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_os_type,
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1760ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_config(struct device *dev,
1761ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				struct device_attribute *attr, char *buf)
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1763ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17647603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* returns null-terminated host config data */
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return strlen(buf);
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1773ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_config = {
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "config",
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_config,
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute *ibmvscsi_attrs[] = {
1782126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	&ibmvscsi_host_vhost_loc,
1783126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	&ibmvscsi_host_vhost_name,
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_srp_version,
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_partition_name,
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_partition_number,
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_mad_version,
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_os_type,
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_config,
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NULL
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI driver registration
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template driver_template = {
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.module = THIS_MODULE,
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_name = "ibmvscsi",
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand = ibmvscsi_queuecommand,
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler = ibmvscsi_eh_abort_handler,
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
18033d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
18040979c84b4affaf924a894380dd0069638b64de03Robert Jennings	.slave_configure = ibmvscsi_slave_configure,
1805742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	.change_queue_depth = ibmvscsi_change_queue_depth,
18067912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
1807a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.this_id = -1,
18094dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	.sg_tablesize = SG_ALL,
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering = ENABLE_CLUSTERING,
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shost_attrs = ibmvscsi_attrs,
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
18157912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
18167912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *
18177912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
18187912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *
18197912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * Return value:
18207912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *	Number of bytes of IO data the driver will need to perform well.
18217912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings */
18227912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jenningsstatic unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
18237912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings{
18247912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	/* iu_storage data allocated in initialize_event_pool */
18254f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	unsigned long desired_io = max_events * sizeof(union viosrp_iu);
18267912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18277912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	/* add io space for sg data */
1828004dd5e88673516a408f0e8e43edbe6a4424be2fBrian King	desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
18297912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	                     IBMVSCSI_CMDS_PER_LUN_DEFAULT);
18307912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18317912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	return desired_io;
18327912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings}
18337912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18340f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
18350f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18360f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	int rc;
18370f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	char *action = "reset";
18380f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18390f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (hostdata->reset_crq) {
18400f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18410f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		hostdata->reset_crq = 0;
18420f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18430f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
18440f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (!rc)
18450f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
1846201aed678482f247aa96bd8fcd9e960fefd82d59Brian King		vio_enable_interrupts(to_vio_dev(hostdata->dev));
18470f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else if (hostdata->reenable_crq) {
18480f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18490f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		action = "enable";
18500f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
18510f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		hostdata->reenable_crq = 0;
18520f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (!rc)
18530f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
18540f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else
18550f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return;
18560f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18570f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (rc) {
18580f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		atomic_set(&hostdata->request_limit, -1);
18590f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		dev_err(hostdata->dev, "error after %s\n", action);
18600f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
18610f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18620f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	scsi_unblock_requests(hostdata->host);
18630f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
18640f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18650f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
18660f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18670f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (kthread_should_stop())
18680f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18690f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	else if (hostdata->reset_crq) {
18700f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18710f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18720f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else if (hostdata->reenable_crq) {
18730f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18740f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18750f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
18760f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18770f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	return 0;
18780f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
18790f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18800f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic int ibmvscsi_work(void *data)
18810f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18820f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	struct ibmvscsi_host_data *hostdata = data;
18830f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	int rc;
18840f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18850f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	set_user_nice(current, -20);
18860f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18870f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	while (1) {
18880f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = wait_event_interruptible(hostdata->work_wait_q,
18890f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King					      ibmvscsi_work_to_do(hostdata));
18900f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18910f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		BUG_ON(rc);
18920f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18930f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (kthread_should_stop())
18940f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			break;
18950f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18960f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		ibmvscsi_do_work(hostdata);
18970f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
18980f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18990f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	return 0;
19000f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
19010f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19027912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings/**
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by bus code for each adapter
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ibmvscsi_host_data *hostdata;
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *host;
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device *dev = &vdev->dev;
19104d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	struct srp_rport_identifiers ids;
19114d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	struct srp_rport *rport;
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long wait_switch = 0;
1913cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	int rc;
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1915559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	dev_set_drvdata(&vdev->dev, NULL);
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!host) {
19196c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't allocate host data\n");
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto scsi_host_alloc_failed;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19234d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	host->transportt = ibmvscsi_transport_template;
19247603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	hostdata = shost_priv(host);
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(hostdata, 0x00, sizeof(*hostdata));
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&hostdata->sent);
19270f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	init_waitqueue_head(&hostdata->work_wait_q);
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hostdata->host = host;
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hostdata->dev = dev;
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&hostdata->request_limit, -1);
19317912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1933126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (map_persist_bufs(hostdata)) {
1934126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(&vdev->dev, "couldn't map persistent buffers\n");
1935126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		goto persist_bufs_failed;
1936126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
1937126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
19380f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
19390f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King					    "ibmvscsi", host->host_no);
19400f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19410f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (IS_ERR(hostdata->work_thread)) {
19420f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
19430f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			PTR_ERR(hostdata->work_thread));
19440f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		goto init_crq_failed;
19450f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
19460f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19474f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
1948cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (rc != 0 && rc != H_RESOURCE) {
19496c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
19500f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		goto kill_kthread;
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19524f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
19536c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't initialize event pool\n");
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto init_pool_failed;
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_lun = 8;
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_id = max_id;
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_channel = max_channel;
1960fbc56f0801f58041a4372a030933bac076b46aadBrian King	host->max_cmd_len = 16;
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (scsi_add_host(hostdata->host, hostdata->dev))
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto add_host_failed;
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19654d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	/* we don't have a proper target_port_id so let's use the fake one */
19664d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	memcpy(ids.port_id, hostdata->madapter_info.partition_name,
19674d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	       sizeof(ids.port_id));
1968aebd5e476ecc8ceb53577b20f2a352ff4ceffd8dFUJITA Tomonori	ids.roles = SRP_RPORT_ROLE_TARGET;
19694d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	rport = srp_rport_add(host, &ids);
19704d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (IS_ERR(rport))
19714d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		goto add_srp_port_failed;
19724d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Try to send an initialization message.  Note that this is allowed
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to fail if the other end is not acive.  In that case we don't
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * want to scan
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1977d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
1978cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	    || rc == H_RESOURCE) {
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Wait around max init_timeout secs for the adapter to finish
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * initializing. When we are done initializing, we will have a
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * valid request_limit.  We don't want Linux scanning before
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we are ready.
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (wait_switch = jiffies + (init_timeout * HZ);
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     time_before(jiffies, wait_switch) &&
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     atomic_read(&hostdata->request_limit) < 2;) {
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			msleep(10);
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* if we now have a valid request_limit, initiate a scan */
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&hostdata->request_limit) > 0)
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_scan_host(host);
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1997559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	dev_set_drvdata(&vdev->dev, hostdata);
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20004d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori      add_srp_port_failed:
20014d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	scsi_remove_host(hostdata->host);
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      add_host_failed:
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_event_pool(&hostdata->pool, hostdata);
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      init_pool_failed:
20054f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
20060f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King      kill_kthread:
20070f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King      kthread_stop(hostdata->work_thread);
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      init_crq_failed:
2009126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unmap_persist_bufs(hostdata);
2010126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King      persist_bufs_failed:
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host_put(host);
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      scsi_host_alloc_failed:
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_remove(struct vio_dev *vdev)
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2018559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
2019126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unmap_persist_bufs(hostdata);
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_event_pool(&hostdata->pool, hostdata);
2021d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
20224f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King					max_events);
20234d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20240f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	kthread_stop(hostdata->work_thread);
20254d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	srp_remove_host(hostdata->host);
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_remove_host(hostdata->host);
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host_put(hostdata->host);
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
203364355b929dec0cb6271e4ac7834c9cf262961e40Brian King * ibmvscsi_resume: Resume from suspend
203464355b929dec0cb6271e4ac7834c9cf262961e40Brian King * @dev:	device struct
203564355b929dec0cb6271e4ac7834c9cf262961e40Brian King *
203664355b929dec0cb6271e4ac7834c9cf262961e40Brian King * We may have lost an interrupt across suspend/resume, so kick the
203764355b929dec0cb6271e4ac7834c9cf262961e40Brian King * interrupt handler
203864355b929dec0cb6271e4ac7834c9cf262961e40Brian King */
203964355b929dec0cb6271e4ac7834c9cf262961e40Brian Kingstatic int ibmvscsi_resume(struct device *dev)
204064355b929dec0cb6271e4ac7834c9cf262961e40Brian King{
204164355b929dec0cb6271e4ac7834c9cf262961e40Brian King	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
204264355b929dec0cb6271e4ac7834c9cf262961e40Brian King	return ibmvscsi_ops->resume(hostdata);
204364355b929dec0cb6271e4ac7834c9cf262961e40Brian King}
204464355b929dec0cb6271e4ac7834c9cf262961e40Brian King
204564355b929dec0cb6271e4ac7834c9cf262961e40Brian King/**
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * support.
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{"vscsi", "IBM,v-scsi"},
2051fb120da678c517f72d4b39932062c2191827b331Stephen Rothwell	{ "", "" }
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
2054915124d8114ec8c3825b10a39151bf9e851593bbStephen Rothwell
205564355b929dec0cb6271e4ac7834c9cf262961e40Brian Kingstatic struct dev_pm_ops ibmvscsi_pm_ops = {
205664355b929dec0cb6271e4ac7834c9cf262961e40Brian King	.resume = ibmvscsi_resume
205764355b929dec0cb6271e4ac7834c9cf262961e40Brian King};
205864355b929dec0cb6271e4ac7834c9cf262961e40Brian King
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct vio_driver ibmvscsi_driver = {
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table = ibmvscsi_device_table,
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe = ibmvscsi_probe,
20626fdf5392caa4c3cba65add0a4beec9f5eb96b723Stephen Rothwell	.remove = ibmvscsi_remove,
20637912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	.get_desired_dma = ibmvscsi_get_desired_dma,
2064cb52d8970eee65bf2c47d9a91bd4f58b17f595f4Benjamin Herrenschmidt	.name = "ibmvscsi",
2065cb52d8970eee65bf2c47d9a91bd4f58b17f595f4Benjamin Herrenschmidt	.pm = &ibmvscsi_pm_ops,
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20684d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonoristatic struct srp_function_template ibmvscsi_transport_functions = {
20694d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori};
20704d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init ibmvscsi_module_init(void)
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20734d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	int ret;
20744d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20754f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	/* Ensure we have two requests to do error recovery */
20764f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	driver_template.can_queue = max_requests;
20774f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	max_events = max_requests + 2;
20784f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King
20797834799a6c8fed36d06d6b78bfd17831ecfa93c4Stephen Rothwell	if (firmware_has_feature(FW_FEATURE_VIO))
2080d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse		ibmvscsi_ops = &rpavscsi_ops;
2081d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	else
2082d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse		return -ENODEV;
2083d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse
20844d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	ibmvscsi_transport_template =
20854d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		srp_attach_transport(&ibmvscsi_transport_functions);
20864d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (!ibmvscsi_transport_template)
20874d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		return -ENOMEM;
20884d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20894d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	ret = vio_register_driver(&ibmvscsi_driver);
20904d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (ret)
20914d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		srp_release_transport(ibmvscsi_transport_template);
20924d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	return ret;
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit ibmvscsi_module_exit(void)
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vio_unregister_driver(&ibmvscsi_driver);
20984d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	srp_release_transport(ibmvscsi_transport_template);
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ibmvscsi_module_init);
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ibmvscsi_module_exit);
2103