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 *
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that some of the underlying infrastructure is different between
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * machines conforming to the "RS/6000 Platform Architecture" (RPA) and
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the older iSeries hypervisor models.  To support both, some low level
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Makefile should pick one, not two, not zero, of these.
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interfaces.  It would be really nice to abstract this above an RDMA
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * layer.
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
735a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
74126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King#include <linux/of.h>
7564355b929dec0cb6271e4ac7834c9cf262961e40Brian King#include <linux/pm.h>
760f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King#include <linux/kthread.h>
77d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse#include <asm/firmware.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/vio.h>
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h>
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h>
834d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori#include <scsi/scsi_transport_srp.h>
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ibmvscsi.h"
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The values below are somewhat arbitrary default values, but
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that there are 3 bits of channel value, 6 bits of id, and
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5 bits of LUN.
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_id = 64;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_channel = 3;
93e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int init_timeout = 300;
94e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int login_timeout = 60;
95e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int info_timeout = 30;
96e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int abort_timeout = 60;
97e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jenningsstatic int reset_timeout = 60;
98a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jenningsstatic int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
994f10aae0d1a285df6b16bf6ca5abd366140fd371Brian Kingstatic int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
100c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic int fast_fail = 1;
101126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic int client_reserve = 1;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1034d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonoristatic struct scsi_transport_template *ibmvscsi_transport_template;
1044d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
105aac3118d33e275a7b1134cb19227c982f4d43877Brian King#define IBMVSCSI_VERSION "1.5.9"
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhousestatic struct ibmvscsi_ops *ibmvscsi_ops;
108d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("IBM Virtual SCSI");
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Dave Boutcher");
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(IBMVSCSI_VERSION);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_id, "Largest ID value for each channel");
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_channel, "Largest channel value");
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
12021465eda9eafa275ed11c27779d90aa95559b6f6Brian Kingmodule_param_named(max_requests, max_requests, int, S_IRUGO);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
122c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsmodule_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
123c1988e3123751fd425fbae99d5c1776608e965a9Robert JenningsMODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
124126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingmodule_param_named(client_reserve, client_reserve, int, S_IRUGO );
125126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian KingMODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for the event pool and event structs
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialize_event_pool: - Allocates and initializes the event pool for a host
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool to be initialized
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @size:	Number of events in pool
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data who owns the event pool
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero on success.
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int initialize_event_pool(struct event_pool *pool,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 int size, struct ibmvscsi_host_data *hostdata)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->size = size;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->next = 0;
1454c021dd136c0ad524e6d117296beafad2bf570c0FUJITA Tomonori	pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pool->events)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pool->iu_storage =
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    dma_alloc_coherent(hostdata->dev,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       pool->size * sizeof(*pool->iu_storage),
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       &pool->iu_token, 0);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pool->iu_storage) {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(pool->events);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < pool->size; ++i) {
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct srp_event_struct *evt = &pool->events[i];
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(&evt->crq, 0x00, sizeof(evt->crq));
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set(&evt->free, 1);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.valid = 0x80;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.IU_length = sizeof(*evt->xfer_iu);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->crq.IU_data_ptr = pool->iu_token +
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sizeof(*evt->xfer_iu) * i;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->xfer_iu = pool->iu_storage + i;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt->hostdata = hostdata;
1684dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		evt->ext_list = NULL;
1694dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		evt->ext_list_token = 0;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release_event_pool: - Frees memory of an event pool of a host
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool to be released
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data who owns the even pool
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero on success.
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void release_event_pool(struct event_pool *pool,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct ibmvscsi_host_data *hostdata)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, in_use = 0;
1864dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	for (i = 0; i < pool->size; ++i) {
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&pool->events[i].free) != 1)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			++in_use;
1894dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		if (pool->events[i].ext_list) {
1904dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			dma_free_coherent(hostdata->dev,
191ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori				  SG_ALL * sizeof(struct srp_direct_buf),
1924dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				  pool->events[i].ext_list,
1934dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				  pool->events[i].ext_list_token);
1944dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		}
1954dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_use)
1976c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_warn(hostdata->dev, "releasing event pool with %d "
1986c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 "events still in use?\n", in_use);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(pool->events);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(hostdata->dev,
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  pool->size * sizeof(*pool->iu_storage),
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  pool->iu_storage, pool->iu_token);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * valid_event_struct: - Determines if event is valid.
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the event
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:	srp_event_struct to be checked for validity
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero if event is invalid, one otherwise.
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int valid_event_struct(struct event_pool *pool,
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct srp_event_struct *evt)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = evt - pool->events;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (index < 0 || index >= pool->size)	/* outside of bounds */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt != pool->events + index)	/* unaligned */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_free-event_struct: - Changes status of event to "free"
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the event
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:	srp_event_struct to be modified
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void free_event_struct(struct event_pool *pool,
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       struct srp_event_struct *evt)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!valid_event_struct(pool, evt)) {
2336c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
2346c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			"(not in pool %p)\n", evt, pool->events);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_inc_return(&evt->free) != 1) {
2386c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(evt->hostdata->dev, "Freeing event_struct %p "
2396c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			"which is not in use!\n", evt);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_evt_struct: - Gets the next free event in pool
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool:	event_pool that contains the events to be searched
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the next event in "free" state, and NULL if none are free.
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that no synchronization is done here, we assume the host_lock
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will syncrhonze things.
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct srp_event_struct *get_event_struct(struct event_pool *pool)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int poolsize = pool->size;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int offset = pool->next;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < poolsize; i++) {
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = (offset + 1) % poolsize;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_dec_if_positive(&pool->events[offset].free)) {
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pool->next = offset;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return &pool->events[offset];
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * init_event_struct: Initialize fields in an event struct that are always
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                    required.
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt:        The event
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @done:       Routine to call when the event is responded to
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @format:     SRP or MAD format
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @timeout:    timeout value set in the CRQ
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_event_struct(struct srp_event_struct *evt_struct,
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      void (*done) (struct srp_event_struct *),
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 format,
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      int timeout)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->cmnd = NULL;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->cmnd_done = NULL;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->sync_srp = NULL;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->crq.format = format;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->crq.timeout = timeout;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct->done = done;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for receiving SCSI responses from the hosting partition
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set_srp_direction: Set the fields in the srp related to data
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     direction and number of buffers based on the direction in
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     the scsi_cmnd and the number of buffers
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_srp_direction(struct scsi_cmnd *cmd,
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct srp_cmd *srp_cmd,
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      int numbuf)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
304ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 fmt;
305ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (numbuf == 0)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
309ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (numbuf == 1)
310ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		fmt = SRP_DATA_DESC_DIRECT;
311ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	else {
312ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		fmt = SRP_DATA_DESC_INDIRECT;
313ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		numbuf = min(numbuf, MAX_INDIRECT_BUFS);
314ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cmd->sc_data_direction == DMA_TO_DEVICE)
316ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			srp_cmd->data_out_desc_cnt = numbuf;
317ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		else
318ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			srp_cmd->data_in_desc_cnt = numbuf;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
320ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
321ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (cmd->sc_data_direction == DMA_TO_DEVICE)
322ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		srp_cmd->buf_fmt = fmt << 4;
323ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	else
324ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		srp_cmd->buf_fmt = fmt;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	srp_cmd whose additional_data member will be unmapped
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	device for which the memory is mapped
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
3334dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomleystatic void unmap_cmd_data(struct srp_cmd *cmd,
3344dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			   struct srp_event_struct *evt_struct,
3354dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			   struct device *dev)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
337ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 out_fmt, in_fmt;
338ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
339ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	out_fmt = cmd->buf_fmt >> 4;
340ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	in_fmt = cmd->buf_fmt & ((1U << 4) - 1);
341ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori
342ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3444dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
345a71fa1fc43a29133f13ae6ada1a389ca298c0934FUJITA Tomonori	if (evt_struct->cmnd)
346a71fa1fc43a29133f13ae6ada1a389ca298c0934FUJITA Tomonori		scsi_dma_unmap(evt_struct->cmnd);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3499413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonoristatic int map_sg_list(struct scsi_cmnd *cmd, int nseg,
350ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		       struct srp_direct_buf *md)
3514dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley{
3524dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	int i;
3539413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	struct scatterlist *sg;
3544dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	u64 total_length = 0;
3554dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
3569413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	scsi_for_each_sg(cmd, sg, nseg, i) {
357ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		struct srp_direct_buf *descr = md + i;
3589413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		descr->va = sg_dma_address(sg);
3599413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		descr->len = sg_dma_len(sg);
360ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		descr->key = 0;
3619413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		total_length += sg_dma_len(sg);
3624dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley 	}
3634dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	return total_length;
3644dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley}
3654dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	Scsi_Cmnd with the scatterlist
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @srp_cmd:	srp_cmd that contains the memory descriptor
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	device for which to map dma memory
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 on success.
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int map_sg_data(struct scsi_cmnd *cmd,
3764dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		       struct srp_event_struct *evt_struct,
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       struct srp_cmd *srp_cmd, struct device *dev)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3804dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	int sg_mapped;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 total_length = 0;
382ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_direct_buf *data =
383ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		(struct srp_direct_buf *) srp_cmd->add_data;
384ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_indirect_buf *indirect =
385ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		(struct srp_indirect_buf *) data;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3879413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	sg_mapped = scsi_dma_map(cmd);
3889413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	if (!sg_mapped)
3899413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		return 1;
3909413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	else if (sg_mapped < 0)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_srp_direction(cmd, srp_cmd, sg_mapped);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* special case; we can use a single direct descriptor */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_mapped == 1) {
3979413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		map_sg_list(cmd, sg_mapped, data);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.va = 0;
402ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
403ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.key = 0;
4044dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
4054dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (sg_mapped <= MAX_INDIRECT_BUFS) {
4069413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori		total_length = map_sg_list(cmd, sg_mapped,
407ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   &indirect->desc_list[0]);
408ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		indirect->len = total_length;
4094dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		return 1;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4124dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	/* get indirect table */
4134dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (!evt_struct->ext_list) {
414ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		evt_struct->ext_list = (struct srp_direct_buf *)
4159413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			dma_alloc_coherent(dev,
416ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   SG_ALL * sizeof(struct srp_direct_buf),
417ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori					   &evt_struct->ext_list_token, 0);
4184dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		if (!evt_struct->ext_list) {
4197912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			if (!firmware_has_feature(FW_FEATURE_CMO))
4207912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				sdev_printk(KERN_ERR, cmd->device,
4217912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				            "Can't allocate memory "
4227912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings				            "for indirect table\n");
423e637d553199e264327714da437e6c808f2f4b096Robert Jennings			scsi_dma_unmap(cmd);
4244dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			return 0;
4254dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		}
4264dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	}
4274dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
4289413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
4294dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
430ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->len = total_length;
431ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.va = evt_struct->ext_list_token;
432ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
433ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	memcpy(indirect->desc_list, evt_struct->ext_list,
434ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	       MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
4354dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley 	return 1;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	struct scsi_cmnd with the memory to be mapped
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @srp_cmd:	srp_cmd that contains the memory descriptor
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	dma device for which to map dma memory
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 on success.
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
4484dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				struct srp_event_struct *evt_struct,
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct srp_cmd *srp_cmd, struct device *dev)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd->sc_data_direction) {
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_FROM_DEVICE:
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_TO_DEVICE:
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_NONE:
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_BIDIRECTIONAL:
4586c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
4596c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "Can't map DMA_BIDIRECTIONAL to read/write\n");
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4626c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
4636c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "Unknown data direction 0x%02x; can't map!\n",
4646c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    cmd->sc_data_direction);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4689413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori	return map_sg_data(cmd, evt_struct, srp_cmd, dev);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4713d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
4723d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * purge_requests: Our virtual adapter just shut down.  purge any sent requests
4733d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @hostdata:    the adapter
4743d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King */
4753d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
4763d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
4771117ef8aed95521f46dae3052c7120baae48c2bbBrian King	struct srp_event_struct *evt;
4783d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	unsigned long flags;
4793d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
4803d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
4811117ef8aed95521f46dae3052c7120baae48c2bbBrian King	while (!list_empty(&hostdata->sent)) {
4821117ef8aed95521f46dae3052c7120baae48c2bbBrian King		evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
4831117ef8aed95521f46dae3052c7120baae48c2bbBrian King		list_del(&evt->list);
4841117ef8aed95521f46dae3052c7120baae48c2bbBrian King		del_timer(&evt->timer);
4851117ef8aed95521f46dae3052c7120baae48c2bbBrian King
4861117ef8aed95521f46dae3052c7120baae48c2bbBrian King		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
4871117ef8aed95521f46dae3052c7120baae48c2bbBrian King		if (evt->cmnd) {
4881117ef8aed95521f46dae3052c7120baae48c2bbBrian King			evt->cmnd->result = (error_code << 16);
4891117ef8aed95521f46dae3052c7120baae48c2bbBrian King			unmap_cmd_data(&evt->iu.srp.cmd, evt,
4901117ef8aed95521f46dae3052c7120baae48c2bbBrian King				       evt->hostdata->dev);
4911117ef8aed95521f46dae3052c7120baae48c2bbBrian King			if (evt->cmnd_done)
4921117ef8aed95521f46dae3052c7120baae48c2bbBrian King				evt->cmnd_done(evt->cmnd);
4931117ef8aed95521f46dae3052c7120baae48c2bbBrian King		} else if (evt->done)
4941117ef8aed95521f46dae3052c7120baae48c2bbBrian King			evt->done(evt);
4951117ef8aed95521f46dae3052c7120baae48c2bbBrian King		free_event_struct(&evt->hostdata->pool, evt);
4961117ef8aed95521f46dae3052c7120baae48c2bbBrian King		spin_lock_irqsave(hostdata->host->host_lock, flags);
4973d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	}
4983d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
4993d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
5003d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5013d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
5023d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_reset_host - Reset the connection to the server
5033d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @hostdata:	struct ibmvscsi_host_data to reset
5043d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
5053d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
5063d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
5073d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	scsi_block_requests(hostdata->host);
5083d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	atomic_set(&hostdata->request_limit, 0);
5093d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5103d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	purge_requests(hostdata, DID_ERROR);
5110f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	hostdata->reset_crq = 1;
5120f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	wake_up(&hostdata->work_wait_q);
5133d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
5143d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5153d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King/**
5163d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_timeout - Internal command timeout handler
5173d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @evt_struct:	struct srp_event_struct that timed out
5183d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King *
5193d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * Called when an internally generated command times out
5203d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
5213d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
5223d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King{
5233d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
5243d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5253d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
5263d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->iu.srp.cmd.opcode);
5273d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5283d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	ibmvscsi_reset_host(hostdata);
5293d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King}
5303d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5313d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for sending and receiving SRPs
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	evt_struct to be sent
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
5393d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @timeout:	timeout in seconds - 0 means do not time command
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that this routine assumes that host_lock is held for synchronization
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
5453d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King				   struct ibmvscsi_host_data *hostdata,
5463d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King				   unsigned long timeout)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
5493c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings	int request_status = 0;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
551f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King	int srp_req = 0;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
553a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	/* If we have exhausted our request limit, just fail this request,
554a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	 * unless it is for a reset or abort.
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note that there are rare cases involving driver generated requests
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (such as task management requests) that the mid layer may think we
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can handle more requests (can_queue) when we actually can't
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
559cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
560f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King		srp_req = 1;
561cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		request_status =
562cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher			atomic_dec_if_positive(&hostdata->request_limit);
563cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		/* If request limit was -1 when we started, it is now even
564cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		 * less than that
565cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		 */
566cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		if (request_status < -1)
567cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher			goto send_error;
568a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		/* Otherwise, we may have run out of requests. */
5693c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		/* If request limit was 0 when we started the adapter is in the
5703c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 * process of performing a login with the server adapter, or
5713c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 * we may have run out of requests.
5723c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		 */
5733c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		else if (request_status == -1 &&
5743c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		         evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
5753c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings			goto send_busy;
576a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		/* Abort and reset calls should make it through.
577a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 * Nothing except abort and reset should use the last two
578a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 * slots unless we had two or less to begin with.
579a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		 */
580a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		else if (request_status < 2 &&
581a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		         evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
582a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			/* In the case that we have less than two requests
583a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * available, check the server limit as a combination
584a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * of the request limit and the number of requests
585a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * in-flight (the size of the send list).  If the
586a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * server limit is greater than 2, return busy so
587a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 * that the last two are reserved for reset and abort.
588a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			 */
589a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			int server_limit = request_status;
590a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			struct srp_event_struct *tmp_evt;
591a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings
592a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			list_for_each_entry(tmp_evt, &hostdata->sent, list) {
593a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings				server_limit++;
594a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			}
595a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings
596a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings			if (server_limit > 2)
597a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings				goto send_busy;
598a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings		}
599cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy the IU into the transfer area */
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*evt_struct->xfer_iu = evt_struct->iu;
603ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add this to the sent list.  We need to do this
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * before we actually send
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in case it comes back REALLY fast
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&evt_struct->list, &hostdata->sent);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6113d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	init_timer(&evt_struct->timer);
6123d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	if (timeout) {
6133d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.data = (unsigned long) evt_struct;
6143d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.expires = jiffies + (timeout * HZ);
6153d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
6163d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		add_timer(&evt_struct->timer);
6173d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	}
6183d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc =
620d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	     ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del(&evt_struct->list);
6223d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		del_timer(&evt_struct->timer);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
624860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
625860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * Firmware will send a CRQ with a transport event (0xFF) to
626860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * tell this client what has happened to the transport.  This
627860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 * will be handled in ibmvscsi_handle_crq()
628860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		 */
629860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rc == H_CLOSED) {
630860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			dev_warn(hostdata->dev, "send warning. "
631860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			         "Receive queue closed, will retry.\n");
632860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			goto send_busy;
633860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
6346c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "send error %d\n", rc);
635f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King		if (srp_req)
636f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King			atomic_inc(&hostdata->request_limit);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send_error;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
642cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher send_busy:
6434dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&hostdata->pool, evt_struct);
646f3a9c4d76a955e331e88992cd3b1e1498c231d52Brian King	if (srp_req && request_status != -1)
6473c887e8a1a4553ae6263fc9490e33de213e3746fRobert Jennings		atomic_inc(&hostdata->request_limit);
648a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	return SCSI_MLQUEUE_HOST_BUSY;
649cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
650cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher send_error:
651cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
652cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
653cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (evt_struct->cmnd != NULL) {
654cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->cmnd->result = DID_ERROR << 16;
655cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->cmnd_done(evt_struct->cmnd);
656cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	} else if (evt_struct->done)
657cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		evt_struct->done(evt_struct);
658cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher
659cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	free_event_struct(&hostdata->pool, evt_struct);
660cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	return 0;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_cmd_rsp: -  Handle responses from commands
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	srp_event_struct to be handled
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used as a callback by when sending scsi cmds.
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gets called by ibmvscsi_handle_crq()
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_cmd_rsp(struct srp_event_struct *evt_struct)
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *cmnd = evt_struct->cmnd;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
675ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(rsp->opcode != SRP_RSP)) {
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
6776c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_warn(evt_struct->hostdata->dev,
6786c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				 "bad SRP RSP type %d\n", rsp->opcode);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmnd) {
682c3a3b55ae80a0d595445064159c69f8e80911e85Brian King		cmnd->result |= rsp->status;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(cmnd->sense_buffer,
685ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			       rsp->data,
686ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			       rsp->sense_data_len);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unmap_cmd_data(&evt_struct->iu.srp.cmd,
6884dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			       evt_struct,
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       evt_struct->hostdata->dev);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		if (rsp->flags & SRP_RSP_FLAG_DOOVER)
6929413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			scsi_set_resid(cmnd, rsp->data_out_res_cnt);
693ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
6949413d7b8aa777dd1fc7db9563ce5e80d769fe7b5FUJITA Tomonori			scsi_set_resid(cmnd, rsp->data_in_res_cnt);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->cmnd_done)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt_struct->cmnd_done(cmnd);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lun_from_dev: - Returns the lun of the scsi device
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev:	struct scsi_device
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 lun_from_dev(struct scsi_device *dev)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_queue: - The queuecommand function of the scsi template
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd:	struct scsi_cmnd to be executed
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @done:	Callback function to be called when cmd is completed
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
716f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 void (*done) (struct scsi_cmnd *))
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_cmd *srp_cmd;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
721ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	struct srp_indirect_buf *indirect;
7227603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmnd->device);
724ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	u8 out_fmt, in_fmt;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
726c3a3b55ae80a0d595445064159c69f8e80911e85Brian King	cmnd->result = (DID_OK << 16);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!evt_struct)
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SCSI_MLQUEUE_HOST_BUSY;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up the actual SRP IU */
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	srp_cmd = &evt_struct->iu.srp.cmd;
733ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
734ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	srp_cmd->opcode = SRP_CMD;
73564a87b244b9297667ca80264aab849a36f494884Boaz Harrosh	memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	srp_cmd->lun = ((u64) lun) << 48;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7384dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
7397912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings		if (!firmware_has_feature(FW_FEATURE_CMO))
7407912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			sdev_printk(KERN_ERR, cmnd->device,
7417912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			            "couldn't convert cmd to srp_cmd\n");
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_event_struct(&hostdata->pool, evt_struct);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SCSI_MLQUEUE_HOST_BUSY;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7464dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	init_event_struct(evt_struct,
7474dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			  handle_cmd_rsp,
7484dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			  VIOSRP_SRP_FORMAT,
749242f9dcb8ba6f68fcd217a119a7648a4f69290e9Jens Axboe			  cmnd->request->timeout/HZ);
7504dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
7514dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	evt_struct->cmnd = cmnd;
7524dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	evt_struct->cmnd_done = done;
7534dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fix up dma address of the buffer itself */
755ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	indirect = (struct srp_indirect_buf *) srp_cmd->add_data;
756ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	out_fmt = srp_cmd->buf_fmt >> 4;
757ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1);
758ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
759ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	     out_fmt == SRP_DATA_DESC_INDIRECT) &&
760ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	    indirect->table_desc.va == 0) {
761ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		indirect->table_desc.va = evt_struct->crq.IU_data_ptr +
762ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			offsetof(struct srp_cmd, add_data) +
763ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori			offsetof(struct srp_indirect_buf, desc_list);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7663d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
769f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic DEF_SCSI_QCMD(ibmvscsi_queuecommand)
770f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzik
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines for driver initialization
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7743507e13fcba6b97501891a410ec8ef9f1f188620Brian King
7753507e13fcba6b97501891a410ec8ef9f1f188620Brian King/**
776126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * map_persist_bufs: - Pre-map persistent data for adapter logins
777126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:   ibmvscsi_host_data of host
778126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
779126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
780126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Return 1 on error, 0 on success.
781126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
782126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
783126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
784126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
785126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
786126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King					     sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
787126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
788126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
789126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
790126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 1;
791126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
792126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
793126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
794126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     &hostdata->madapter_info,
795126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     sizeof(hostdata->madapter_info),
796126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King						     DMA_BIDIRECTIONAL);
797126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
798126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
799126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dma_unmap_single(hostdata->dev, hostdata->caps_addr,
800126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
801126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 1;
802126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
803126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
804126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return 0;
805126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
806126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
807126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
808126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
809126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:   ibmvscsi_host_data of host
810126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
811126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Unmap the capabilities and adapter info DMA buffers
812126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
813126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
814126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
815126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	dma_unmap_single(hostdata->dev, hostdata->caps_addr,
816126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
817126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
818126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
819126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			 sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
820126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
821126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
822126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
8233507e13fcba6b97501891a410ec8ef9f1f188620Brian King * login_rsp: - Handle response to SRP login request
8243507e13fcba6b97501891a410ec8ef9f1f188620Brian King * @evt_struct:	srp_event_struct with the response
8253507e13fcba6b97501891a410ec8ef9f1f188620Brian King *
8263507e13fcba6b97501891a410ec8ef9f1f188620Brian King * Used as a "done" callback by when sending srp_login. Gets called
8273507e13fcba6b97501891a410ec8ef9f1f188620Brian King * by ibmvscsi_handle_crq()
8283507e13fcba6b97501891a410ec8ef9f1f188620Brian King*/
8293507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic void login_rsp(struct srp_event_struct *evt_struct)
8303507e13fcba6b97501891a410ec8ef9f1f188620Brian King{
8313507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
8323507e13fcba6b97501891a410ec8ef9f1f188620Brian King	switch (evt_struct->xfer_iu->srp.login_rsp.opcode) {
8333507e13fcba6b97501891a410ec8ef9f1f188620Brian King	case SRP_LOGIN_RSP:	/* it worked! */
8343507e13fcba6b97501891a410ec8ef9f1f188620Brian King		break;
8353507e13fcba6b97501891a410ec8ef9f1f188620Brian King	case SRP_LOGIN_REJ:	/* refused! */
8363507e13fcba6b97501891a410ec8ef9f1f188620Brian King		dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
8373507e13fcba6b97501891a410ec8ef9f1f188620Brian King			 evt_struct->xfer_iu->srp.login_rej.reason);
8383507e13fcba6b97501891a410ec8ef9f1f188620Brian King		/* Login failed.  */
8393507e13fcba6b97501891a410ec8ef9f1f188620Brian King		atomic_set(&hostdata->request_limit, -1);
8403507e13fcba6b97501891a410ec8ef9f1f188620Brian King		return;
8413507e13fcba6b97501891a410ec8ef9f1f188620Brian King	default:
8423507e13fcba6b97501891a410ec8ef9f1f188620Brian King		dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
8433507e13fcba6b97501891a410ec8ef9f1f188620Brian King			evt_struct->xfer_iu->srp.login_rsp.opcode);
8443507e13fcba6b97501891a410ec8ef9f1f188620Brian King		/* Login failed.  */
8453507e13fcba6b97501891a410ec8ef9f1f188620Brian King		atomic_set(&hostdata->request_limit, -1);
8463507e13fcba6b97501891a410ec8ef9f1f188620Brian King		return;
8473507e13fcba6b97501891a410ec8ef9f1f188620Brian King	}
8483507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8493507e13fcba6b97501891a410ec8ef9f1f188620Brian King	dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
850126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->client_migrated = 0;
8513507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8523507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* Now we know what the real request-limit is.
8533507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * This value is set rather than added to request_limit because
8543507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * request_limit could have been set to -1 by this client.
8553507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 */
8563507e13fcba6b97501891a410ec8ef9f1f188620Brian King	atomic_set(&hostdata->request_limit,
8573507e13fcba6b97501891a410ec8ef9f1f188620Brian King		   evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
8583507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8593507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* If we had any pending I/Os, kick them */
8603507e13fcba6b97501891a410ec8ef9f1f188620Brian King	scsi_unblock_requests(hostdata->host);
8613507e13fcba6b97501891a410ec8ef9f1f188620Brian King}
8623507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8633507e13fcba6b97501891a410ec8ef9f1f188620Brian King/**
8643507e13fcba6b97501891a410ec8ef9f1f188620Brian King * send_srp_login: - Sends the srp login
8653507e13fcba6b97501891a410ec8ef9f1f188620Brian King * @hostdata:	ibmvscsi_host_data of host
8663507e13fcba6b97501891a410ec8ef9f1f188620Brian King *
8673507e13fcba6b97501891a410ec8ef9f1f188620Brian King * Returns zero if successful.
8683507e13fcba6b97501891a410ec8ef9f1f188620Brian King*/
8693507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic int send_srp_login(struct ibmvscsi_host_data *hostdata)
8703507e13fcba6b97501891a410ec8ef9f1f188620Brian King{
8713507e13fcba6b97501891a410ec8ef9f1f188620Brian King	int rc;
8723507e13fcba6b97501891a410ec8ef9f1f188620Brian King	unsigned long flags;
8733507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct srp_login_req *login;
8743507e13fcba6b97501891a410ec8ef9f1f188620Brian King	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
8753507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8763507e13fcba6b97501891a410ec8ef9f1f188620Brian King	BUG_ON(!evt_struct);
8773507e13fcba6b97501891a410ec8ef9f1f188620Brian King	init_event_struct(evt_struct, login_rsp,
8783507e13fcba6b97501891a410ec8ef9f1f188620Brian King			  VIOSRP_SRP_FORMAT, login_timeout);
8793507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8803507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login = &evt_struct->iu.srp.login_req;
8813507e13fcba6b97501891a410ec8ef9f1f188620Brian King	memset(login, 0, sizeof(*login));
8823507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->opcode = SRP_LOGIN_REQ;
8833507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->req_it_iu_len = sizeof(union srp_iu);
8843507e13fcba6b97501891a410ec8ef9f1f188620Brian King	login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
8853507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8863507e13fcba6b97501891a410ec8ef9f1f188620Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
8873507e13fcba6b97501891a410ec8ef9f1f188620Brian King	/* Start out with a request limit of 0, since this is negotiated in
8883507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * the login request we are just sending and login requests always
8893507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 * get sent by the driver regardless of request_limit.
8903507e13fcba6b97501891a410ec8ef9f1f188620Brian King	 */
8913507e13fcba6b97501891a410ec8ef9f1f188620Brian King	atomic_set(&hostdata->request_limit, 0);
8923507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8933507e13fcba6b97501891a410ec8ef9f1f188620Brian King	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
8943507e13fcba6b97501891a410ec8ef9f1f188620Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
8953507e13fcba6b97501891a410ec8ef9f1f188620Brian King	dev_info(hostdata->dev, "sent SRP login\n");
8963507e13fcba6b97501891a410ec8ef9f1f188620Brian King	return rc;
8973507e13fcba6b97501891a410ec8ef9f1f188620Brian King};
8983507e13fcba6b97501891a410ec8ef9f1f188620Brian King
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
900126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * capabilities_rsp: - Handle response to MAD adapter capabilities request
901126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @evt_struct:	srp_event_struct with the response
902126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *
903126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * Used as a "done" callback by when sending adapter_info.
904126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
905126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void capabilities_rsp(struct srp_event_struct *evt_struct)
906126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
907126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
908126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
909126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (evt_struct->xfer_iu->mad.capabilities.common.status) {
910126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
911126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			evt_struct->xfer_iu->mad.capabilities.common.status);
912126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	} else {
913126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP)
914126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			dev_info(hostdata->dev, "Partition migration not supported\n");
915126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
916126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		if (client_reserve) {
917126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			if (hostdata->caps.reserve.common.server_support ==
918126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			    SERVER_SUPPORTS_CAP)
919126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				dev_info(hostdata->dev, "Client reserve enabled\n");
920126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			else
921126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				dev_info(hostdata->dev, "Client reserve not supported\n");
922126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		}
923126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
924126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
925126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	send_srp_login(hostdata);
926126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
927126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
928126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
929126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * send_mad_capabilities: - Sends the mad capabilities request
930126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King *      and stores the result so it can be retrieved with
931126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King * @hostdata:	ibmvscsi_host_data of host
932126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King */
933126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
934126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
935126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct viosrp_capabilities *req;
936126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct srp_event_struct *evt_struct;
937126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unsigned long flags;
93861c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	struct device_node *of_node = hostdata->dev->of_node;
939126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	const char *location;
940126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
941126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	evt_struct = get_event_struct(&hostdata->pool);
942126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	BUG_ON(!evt_struct);
943126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
944126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	init_event_struct(evt_struct, capabilities_rsp,
945126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			  VIOSRP_MAD_FORMAT, info_timeout);
946126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
947126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req = &evt_struct->iu.mad.capabilities;
948126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	memset(req, 0, sizeof(*req));
949126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
950126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.flags = CAP_LIST_SUPPORTED;
951126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (hostdata->client_migrated)
952126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.flags |= CLIENT_MIGRATED;
953126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
954126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
955126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		sizeof(hostdata->caps.name));
956126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0';
957126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
958126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	location = of_get_property(of_node, "ibm,loc-code", NULL);
959126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	location = location ? location : dev_name(hostdata->dev);
960126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
961126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0';
962126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
963126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->common.type = VIOSRP_CAPABILITIES_TYPE;
964126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->buffer = hostdata->caps_addr;
965126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
966126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES;
967126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration);
968126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP;
969126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	hostdata->caps.migration.ecl = 1;
970126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
971126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (client_reserve) {
972126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES;
973126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve);
974126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP;
975126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2;
976126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		req->common.length = sizeof(hostdata->caps);
977126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	} else
978126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve);
979126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
980126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
981126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
982126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
983126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
984126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
985126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
986126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King/**
987c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * fast_fail_rsp: - Handle response to MAD enable fast fail
988c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * @evt_struct:	srp_event_struct with the response
989c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings *
990c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * Used as a "done" callback by when sending enable fast fail. Gets called
991c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * by ibmvscsi_handle_crq()
992c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings */
993c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic void fast_fail_rsp(struct srp_event_struct *evt_struct)
994c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings{
995c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
996c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status;
997c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
998c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	if (status == VIOSRP_MAD_NOT_SUPPORTED)
999c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "fast_fail not supported in server\n");
1000c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	else if (status == VIOSRP_MAD_FAILED)
1001c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "fast_fail request failed\n");
1002c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	else if (status != VIOSRP_MAD_SUCCESS)
1003c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings		dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
1004c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1005126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	send_mad_capabilities(hostdata);
1006c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings}
1007c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1008c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings/**
1009c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * init_host - Start host initialization
1010c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * @hostdata:	ibmvscsi_host_data of host
1011c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings *
1012c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings * Returns zero if successful.
1013c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings */
1014c1988e3123751fd425fbae99d5c1776608e965a9Robert Jenningsstatic int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
1015c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings{
1016c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	int rc;
1017c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	unsigned long flags;
1018c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct viosrp_fast_fail *fast_fail_mad;
1019c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	struct srp_event_struct *evt_struct;
1020c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1021126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (!fast_fail) {
1022126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		send_mad_capabilities(hostdata);
1023126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		return 0;
1024126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
1025c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1026c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	evt_struct = get_event_struct(&hostdata->pool);
1027c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	BUG_ON(!evt_struct);
1028c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1029c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
1030c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1031c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad = &evt_struct->iu.mad.fast_fail;
1032c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
1033c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL;
1034c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	fast_fail_mad->common.length = sizeof(*fast_fail_mad);
1035c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1036c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	spin_lock_irqsave(hostdata->host->host_lock, flags);
1037c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
1038c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1039c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings	return rc;
1040c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings}
1041c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings
1042c1988e3123751fd425fbae99d5c1776608e965a9Robert Jennings/**
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter_info_rsp: - Handle response to MAD adapter info request
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @evt_struct:	srp_event_struct with the response
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used as a "done" callback by when sending adapter_info. Gets called
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by ibmvscsi_handle_crq()
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adapter_info_rsp(struct srp_event_struct *evt_struct)
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
10546c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "error %d getting adapter info\n",
10556c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			evt_struct->xfer_iu->mad.adapter_info.common.status);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10576c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_info(hostdata->dev, "host srp version: %s, "
10586c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 "host partition %s (%d), OS %d, max io %u\n",
10596c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.srp_version,
10606c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.partition_name,
10616c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.partition_number,
10626c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.os_type,
10636c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			 hostdata->madapter_info.port_max_txu[0]);
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (hostdata->madapter_info.port_max_txu[0])
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hostdata->host->max_sectors =
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hostdata->madapter_info.port_max_txu[0] >> 9;
1068154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher
1069154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		if (hostdata->madapter_info.os_type == 3 &&
1070154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
10716c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
10726c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				hostdata->madapter_info.srp_version);
10736c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
10746c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				MAX_INDIRECT_BUFS);
1075154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
1076154fb614df83086ceb18a2c19908154e78d4dc98Dave C Boutcher		}
1077e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King
1078e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King		if (hostdata->madapter_info.os_type == 3) {
1079e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King			enable_fast_fail(hostdata);
1080e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King			return;
1081e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King		}
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10833507e13fcba6b97501891a410ec8ef9f1f188620Brian King
1084e08afeb7e69f45e4ab9fbb8530fe433484b96606Brian King	send_srp_login(hostdata);
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send_mad_adapter_info: - Sends the mad adapter info request
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      and stores the result so it can be retrieved with
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      sysfs.  We COULD consider causing a failure if the
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      returned SRP version doesn't match ours.
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns zero if successful.
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct viosrp_adapter_info *req;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
110006f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	unsigned long flags;
1101e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
11033507e13fcba6b97501891a410ec8ef9f1f188620Brian King	BUG_ON(!evt_struct);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_event_struct(evt_struct,
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  adapter_info_rsp,
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  VIOSRP_MAD_FORMAT,
1108e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings			  info_timeout);
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = &evt_struct->iu.mad.adapter_info;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(req, 0x00, sizeof(*req));
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req->common.length = sizeof(hostdata->madapter_info);
1115126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	req->buffer = hostdata->adapter_info_addr;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111706f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
1118126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
11196c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
112006f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11243507e13fcba6b97501891a410ec8ef9f1f188620Brian King * init_adapter: Start virtual adapter initialization sequence
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11263507e13fcba6b97501891a410ec8ef9f1f188620Brian King */
11273507e13fcba6b97501891a410ec8ef9f1f188620Brian Kingstatic void init_adapter(struct ibmvscsi_host_data *hostdata)
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_mad_adapter_info(hostdata);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sync_completion: Signal that a synchronous command has completed
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that after returning from this call, the evt_struct is freed.
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the caller waiting on this completion shouldn't touch the evt_struct
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * again.
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sync_completion(struct srp_event_struct *evt_struct)
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy the response back */
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->sync_srp)
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*evt_struct->sync_srp = *evt_struct->xfer_iu;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	complete(&evt_struct->comp);
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_abort: Abort a command...from scsi host template
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send this over to the server and wait synchronously for the response
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11537603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_tsk_mgmt *tsk_mgmt;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *tmp_evt, *found_evt;
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union viosrp_iu srp_rsp;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rsp_rc;
1159be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	unsigned long flags;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmd->device);
1161860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	unsigned long wait_switch = 0;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First, find this command in our sent list so we can figure
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * out the correct tag
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1166be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
1167860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	wait_switch = jiffies + (init_timeout * HZ);
1168860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	do {
1169860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		found_evt = NULL;
1170860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
1171860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			if (tmp_evt->cmnd == cmd) {
1172860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				found_evt = tmp_evt;
1173860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				break;
1174860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			}
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1177860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (!found_evt) {
1178860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1179860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return SUCCESS;
1180860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1182860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt = get_event_struct(&hostdata->pool);
1183860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (evt == NULL) {
1184860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1185860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			sdev_printk(KERN_ERR, cmd->device,
1186860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				"failed to allocate abort event\n");
1187860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return FAILED;
1188860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1190860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_event_struct(evt,
1191860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  sync_completion,
1192860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  VIOSRP_SRP_FORMAT,
1193e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings				  abort_timeout);
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1195860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1197860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* Set up an abort SRP command */
1198860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
1199860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->opcode = SRP_TSK_MGMT;
1200860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->lun = ((u64) lun) << 48;
1201860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
1202860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->task_tag = (u64) found_evt;
1203860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1204860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt->sync_srp = &srp_rsp;
1205860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1206860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_completion(&evt->comp);
1207e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
1208860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1209860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
1210860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			break;
1211860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1212860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1213860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		msleep(10);
1214860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_lock_irqsave(hostdata->host->host_lock, flags);
1215860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	} while (time_before(jiffies, wait_switch));
1216860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1217be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1218860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1219be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	if (rsp_rc != 0) {
12206c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
12216c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "failed to send abort() event. rc=%d\n", rsp_rc);
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1225860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	sdev_printk(KERN_INFO, cmd->device,
1226fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar                    "aborting command. lun 0x%llx, tag 0x%llx\n",
1227860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		    (((u64) lun) << 48), (u64) found_evt);
1228860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_for_completion(&evt->comp);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure we got a good response */
1232ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
12346c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
12356c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    srp_rsp.srp.rsp.opcode);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1239ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
1240ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rsp_rc = srp_rsp.srp.rsp.status;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rsp_rc) {
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
12466c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device,
1247fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar				    "abort code %d for task tag 0x%llx\n",
12486c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    rsp_rc, tsk_mgmt->task_tag);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Because we dropped the spinlock above, it's possible
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The event is no longer in our list.  Make sure it didn't
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * complete while we were aborting
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1256be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found_evt = NULL;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp_evt->cmnd == cmd) {
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found_evt = tmp_evt;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (found_evt == NULL) {
1266be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1267fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar		sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
12686c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    tsk_mgmt->task_tag);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SUCCESS;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1272fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
12736c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		    tsk_mgmt->task_tag);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->result = (DID_ABORT << 16);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&found_evt->list);
12774dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
12784dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley		       found_evt->hostdata->dev);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&found_evt->hostdata->pool, found_evt);
1280be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&hostdata->request_limit);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * template send this over to the server and wait synchronously for the
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * response
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12927603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_tsk_mgmt *tsk_mgmt;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *tmp_evt, *pos;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union viosrp_iu srp_rsp;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rsp_rc;
1298be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	unsigned long flags;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 lun = lun_from_dev(cmd->device);
1300860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	unsigned long wait_switch = 0;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1302be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
1303860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	wait_switch = jiffies + (init_timeout * HZ);
1304860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	do {
1305860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt = get_event_struct(&hostdata->pool);
1306860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (evt == NULL) {
1307860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1308860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			sdev_printk(KERN_ERR, cmd->device,
1309860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				"failed to allocate reset event\n");
1310860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			return FAILED;
1311860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		}
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1313860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_event_struct(evt,
1314860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  sync_completion,
1315860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings				  VIOSRP_SRP_FORMAT,
1316e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings				  reset_timeout);
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1318860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1320860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		/* Set up a lun reset SRP command */
1321860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
1322860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->opcode = SRP_TSK_MGMT;
1323860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->lun = ((u64) lun) << 48;
1324860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1326860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		evt->sync_srp = &srp_rsp;
1327860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1328860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		init_completion(&evt->comp);
1329e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
1330860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1331860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
1332860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings			break;
1333860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1334860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1335860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		msleep(10);
1336860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		spin_lock_irqsave(hostdata->host->host_lock, flags);
1337860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings	} while (time_before(jiffies, wait_switch));
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1339be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1340860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
1341be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	if (rsp_rc != 0) {
13426c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		sdev_printk(KERN_ERR, cmd->device,
13436c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			    "failed to send reset event. rc=%d\n", rsp_rc);
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1347fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
1348860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings		    (((u64) lun) << 48));
1349860784c8a2b077157b6a51fb8749524d0363cc49Robert Jennings
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_for_completion(&evt->comp);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure we got a good response */
1353ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
13556c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
13566c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    srp_rsp.srp.rsp.opcode);
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1360ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
1361ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rsp_rc = srp_rsp.srp.rsp.status;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rsp_rc) {
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (printk_ratelimit())
13676c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			sdev_printk(KERN_WARNING, cmd->device,
1368fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar				    "reset code %d for task tag 0x%llx\n",
13696c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				    rsp_rc, tsk_mgmt->task_tag);
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We need to find all commands for this LUN that have not yet been
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * responded to, and fail them with DID_RESET
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1376be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_lock_irqsave(hostdata->host->host_lock, flags);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_evt->cmnd)
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->cmnd->result = (DID_RESET << 16);
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del(&tmp_evt->list);
13824dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley			unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
13834dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley				       tmp_evt->hostdata->dev);
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_event_struct(&tmp_evt->hostdata->pool,
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   tmp_evt);
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			atomic_inc(&hostdata->request_limit);
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_evt->cmnd_done)
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->cmnd_done(tmp_evt->cmnd);
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (tmp_evt->done)
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp_evt->done(tmp_evt);
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1393be042f240a8528b8f6b741a484cdbbf515698388Dave C Boutcher	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13983d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
13993d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King * @cmd:	struct scsi_cmnd having problems
14003d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King*/
14013d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian Kingstatic int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14033d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	unsigned long wait_switch = 0;
14047603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14063d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
14073d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14083d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	ibmvscsi_reset_host(hostdata);
14093d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14103d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	for (wait_switch = jiffies + (init_timeout * HZ);
14113d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	     time_before(jiffies, wait_switch) &&
14123d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		     atomic_read(&hostdata->request_limit) < 2;) {
14133d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14143d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		msleep(10);
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14163d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14173d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	if (atomic_read(&hostdata->request_limit) <= 0)
14183d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King		return FAILED;
14193d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
14203d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	return SUCCESS;
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @crq:	Command/Response queue
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hostdata:	ibmvscsi_host_data of host
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ibmvscsi_handle_crq(struct viosrp_crq *crq,
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct ibmvscsi_host_data *hostdata)
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14326c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King	long rc;
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct =
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (struct srp_event_struct *)crq->IU_data_ptr;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (crq->valid) {
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xC0:		/* initialization */
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (crq->format) {
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x01:	/* Initialization message */
14406c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "partner initialized\n");
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Send back a response */
1442d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse			if ((rc = ibmvscsi_ops->send_crq(hostdata,
1443d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse							 0xC002000000000000LL, 0)) == 0) {
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Now login */
14453507e13fcba6b97501891a410ec8ef9f1f188620Brian King				init_adapter(hostdata);
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
14476c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x02:	/* Initialization response */
14526c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "partner initialization complete\n");
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Now login */
14553507e13fcba6b97501891a410ec8ef9f1f188620Brian King			init_adapter(hostdata);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
14586c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14612b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher	case 0xFF:	/* Hypervisor telling us the connection is closed */
14622b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		scsi_block_requests(hostdata->host);
1463cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher		atomic_set(&hostdata->request_limit, 0);
14642b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		if (crq->format == 0x06) {
14652b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher			/* We need to re-setup the interpartition connection */
14666c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_info(hostdata->dev, "Re-enabling adapter!\n");
1467126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King			hostdata->client_migrated = 1;
14680f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			hostdata->reenable_crq = 1;
14692b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher			purge_requests(hostdata, DID_REQUEUE);
14700f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			wake_up(&hostdata->work_wait_q);
14712b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		} else {
14726c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
14736c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King				crq->format);
14740f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			ibmvscsi_reset_host(hostdata);
14752b541f8f77fd339e4c5c5cbe8549b52445012704Dave C Boutcher		}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x80:		/* real payload */
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
14806c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
14816c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			crq->valid);
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The only kind of payload CRQs we should get are responses to
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * things we send. Make sure this response is to something we
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * actually sent
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!valid_event_struct(&hostdata->pool, evt_struct)) {
14906c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (void *)crq->IU_data_ptr);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&evt_struct->free)) {
14966c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
14976c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King			(void *)crq->IU_data_ptr);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (crq->format == VIOSRP_SRP_FORMAT)
1502ef265673434680f2307ceafae4a2badc657e94ccFUJITA Tomonori		atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   &hostdata->request_limit);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15053d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	del_timer(&evt_struct->timer);
15063d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King
1507ca61668b82a902143997794aae3f681a602e6ebcBrian King	if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
1508c3a3b55ae80a0d595445064159c69f8e80911e85Brian King		evt_struct->cmnd->result = DID_ERROR << 16;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (evt_struct->done)
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		evt_struct->done(evt_struct);
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
15126c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Lock the host_lock before messing with these structures, since we
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * are running in a task context
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&evt_struct->list);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_event_struct(&evt_struct->hostdata->pool, evt_struct);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_get_host_config: Send the command to the server to get host
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configuration data.  The data is opaque to us.
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned char *buffer, int length)
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct viosrp_host_config *host_config;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct srp_event_struct *evt_struct;
153306f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	unsigned long flags;
1534e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	dma_addr_t addr;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	evt_struct = get_event_struct(&hostdata->pool);
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!evt_struct) {
15396c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_event_struct(evt_struct,
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  sync_completion,
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  VIOSRP_MAD_FORMAT,
1546e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings			  info_timeout);
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config = &evt_struct->iu.mad.host_config;
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up a lun reset SRP command */
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(host_config, 0x00, sizeof(*host_config));
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host_config->common.length = length;
1554e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	host_config->buffer = addr = dma_map_single(hostdata->dev, buffer,
1555e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori						    length,
1556e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori						    DMA_BIDIRECTIONAL);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15588d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori	if (dma_mapping_error(hostdata->dev, host_config->buffer)) {
15597912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings		if (!firmware_has_feature(FW_FEATURE_CMO))
15607912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			dev_err(hostdata->dev,
15617912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings			        "dma_mapping error getting host config\n");
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_event_struct(&hostdata->pool, evt_struct);
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_completion(&evt_struct->comp);
156706f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_lock_irqsave(hostdata->host->host_lock, flags);
1568e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
156906f923cbf080e22d1ffccbf3fd2cbab0176f6025Brian King	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1570e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	if (rc == 0)
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wait_for_completion(&evt_struct->comp);
1572e5dbfa6621732a110514fb10f9a43f0e8f4befd4FUJITA Tomonori	dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15770979c84b4affaf924a894380dd0069638b64de03Robert Jennings/**
15780979c84b4affaf924a894380dd0069638b64de03Robert Jennings * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
15790979c84b4affaf924a894380dd0069638b64de03Robert Jennings * @sdev:	struct scsi_device device to configure
15800979c84b4affaf924a894380dd0069638b64de03Robert Jennings *
15810979c84b4affaf924a894380dd0069638b64de03Robert Jennings * Enable allow_restart for a device if it is a disk.  Adjust the
15820979c84b4affaf924a894380dd0069638b64de03Robert Jennings * queue_depth here also as is required by the documentation for
15830979c84b4affaf924a894380dd0069638b64de03Robert Jennings * struct scsi_host_template.
15840979c84b4affaf924a894380dd0069638b64de03Robert Jennings */
15850979c84b4affaf924a894380dd0069638b64de03Robert Jenningsstatic int ibmvscsi_slave_configure(struct scsi_device *sdev)
15860979c84b4affaf924a894380dd0069638b64de03Robert Jennings{
15870979c84b4affaf924a894380dd0069638b64de03Robert Jennings	struct Scsi_Host *shost = sdev->host;
15880979c84b4affaf924a894380dd0069638b64de03Robert Jennings	unsigned long lock_flags = 0;
15890979c84b4affaf924a894380dd0069638b64de03Robert Jennings
15900979c84b4affaf924a894380dd0069638b64de03Robert Jennings	spin_lock_irqsave(shost->host_lock, lock_flags);
1591d1a357fcc8348d325d151f6fe0ea54e317652457Brian King	if (sdev->type == TYPE_DISK) {
15920979c84b4affaf924a894380dd0069638b64de03Robert Jennings		sdev->allow_restart = 1;
1593e1a5ce5b88d06344caec0c71b4ee33e7296358ddRobert Jennings		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
1594d1a357fcc8348d325d151f6fe0ea54e317652457Brian King	}
15950979c84b4affaf924a894380dd0069638b64de03Robert Jennings	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
15960979c84b4affaf924a894380dd0069638b64de03Robert Jennings	spin_unlock_irqrestore(shost->host_lock, lock_flags);
15970979c84b4affaf924a894380dd0069638b64de03Robert Jennings	return 0;
15980979c84b4affaf924a894380dd0069638b64de03Robert Jennings}
15990979c84b4affaf924a894380dd0069638b64de03Robert Jennings
1600742d25b819f11dce91b89e6c9ac17402a119f20aBrian King/**
1601742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * ibmvscsi_change_queue_depth - Change the device's queue depth
1602742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * @sdev:	scsi device struct
1603742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * @qdepth:	depth to set
1604e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie * @reason:	calling context
1605742d25b819f11dce91b89e6c9ac17402a119f20aBrian King *
1606742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * Return value:
1607742d25b819f11dce91b89e6c9ac17402a119f20aBrian King * 	actual depth set
1608742d25b819f11dce91b89e6c9ac17402a119f20aBrian King **/
1609e881a172dac4d9ea3b2a1540041d872963c269bdMike Christiestatic int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth,
1610e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie				       int reason)
1611742d25b819f11dce91b89e6c9ac17402a119f20aBrian King{
1612e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie	if (reason != SCSI_QDEPTH_DEFAULT)
1613e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie		return -EOPNOTSUPP;
1614e881a172dac4d9ea3b2a1540041d872963c269bdMike Christie
1615742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
1616742d25b819f11dce91b89e6c9ac17402a119f20aBrian King		qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
1617742d25b819f11dce91b89e6c9ac17402a119f20aBrian King
1618742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	scsi_adjust_queue_depth(sdev, 0, qdepth);
1619742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	return sdev->queue_depth;
1620742d25b819f11dce91b89e6c9ac17402a119f20aBrian King}
1621742d25b819f11dce91b89e6c9ac17402a119f20aBrian King
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sysfs attributes
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1625126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic ssize_t show_host_vhost_loc(struct device *dev,
1626126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				   struct device_attribute *attr, char *buf)
1627126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
1628126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct Scsi_Host *shost = class_to_shost(dev);
1629126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
1630126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	int len;
1631126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1632126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
1633126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		       hostdata->caps.loc);
1634126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return len;
1635126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
1636126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1637126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic struct device_attribute ibmvscsi_host_vhost_loc = {
1638126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.attr = {
1639126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .name = "vhost_loc",
1640126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .mode = S_IRUGO,
1641126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 },
1642126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.show = show_host_vhost_loc,
1643126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
1644126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1645126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic ssize_t show_host_vhost_name(struct device *dev,
1646126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King				    struct device_attribute *attr, char *buf)
1647126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King{
1648126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct Scsi_Host *shost = class_to_shost(dev);
1649126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
1650126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	int len;
1651126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1652126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
1653126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		       hostdata->caps.name);
1654126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	return len;
1655126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King}
1656126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1657126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian Kingstatic struct device_attribute ibmvscsi_host_vhost_name = {
1658126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.attr = {
1659126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .name = "vhost_name",
1660126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 .mode = S_IRUGO,
1661126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		 },
1662126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	.show = show_host_vhost_name,
1663126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King};
1664126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
1665ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_srp_version(struct device *dev,
1666ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				     struct device_attribute *attr, char *buf)
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1668ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
16697603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%s\n",
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.srp_version);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1677ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_srp_version = {
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "srp_version",
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_srp_version,
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1685ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_partition_name(struct device *dev,
1686ee959b00c335d7780136c5abda37809191fe52c3Tony Jones					struct device_attribute *attr,
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					char *buf)
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1689ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
16907603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%s\n",
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.partition_name);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1698ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_partition_name = {
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "partition_name",
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_partition_name,
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1706ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_partition_number(struct device *dev,
1707ee959b00c335d7780136c5abda37809191fe52c3Tony Jones					  struct device_attribute *attr,
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  char *buf)
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1710ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17117603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n",
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.partition_number);
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1719ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_partition_number = {
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "partition_number",
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_partition_number,
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1727ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_mad_version(struct device *dev,
1728ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				     struct device_attribute *attr, char *buf)
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1730ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17317603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n",
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hostdata->madapter_info.mad_version);
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1739ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_mad_version = {
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "mad_version",
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_mad_version,
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1747ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_os_type(struct device *dev,
1748ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				 struct device_attribute *attr, char *buf)
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1750ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17517603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1758ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_os_type = {
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "os_type",
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_os_type,
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1766ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic ssize_t show_host_config(struct device *dev,
1767ee959b00c335d7780136c5abda37809191fe52c3Tony Jones				struct device_attribute *attr, char *buf)
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1769ee959b00c335d7780136c5abda37809191fe52c3Tony Jones	struct Scsi_Host *shost = class_to_shost(dev);
17707603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* returns null-terminated host config data */
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return strlen(buf);
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1779ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute ibmvscsi_host_config = {
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr = {
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .name = "config",
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 .mode = S_IRUGO,
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 },
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = show_host_config,
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1787ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic struct device_attribute *ibmvscsi_attrs[] = {
1788126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	&ibmvscsi_host_vhost_loc,
1789126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	&ibmvscsi_host_vhost_name,
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_srp_version,
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_partition_name,
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_partition_number,
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_mad_version,
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_os_type,
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&ibmvscsi_host_config,
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NULL
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI driver registration
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template driver_template = {
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.module = THIS_MODULE,
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_name = "ibmvscsi",
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand = ibmvscsi_queuecommand,
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler = ibmvscsi_eh_abort_handler,
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
18093d0e91f7ace12499c4b00088e9a6b1361e1bb0caBrian King	.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
18100979c84b4affaf924a894380dd0069638b64de03Robert Jennings	.slave_configure = ibmvscsi_slave_configure,
1811742d25b819f11dce91b89e6c9ac17402a119f20aBrian King	.change_queue_depth = ibmvscsi_change_queue_depth,
18127912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
1813a897ff2a6386ac4368ba41db18b626afd903f9d8Robert Jennings	.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.this_id = -1,
18154dddbc26c3895ecdab1f4b16435685b47f96f599James Bottomley	.sg_tablesize = SG_ALL,
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering = ENABLE_CLUSTERING,
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shost_attrs = ibmvscsi_attrs,
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
18217912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
18227912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *
18237912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
18247912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *
18257912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings * Return value:
18267912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings *	Number of bytes of IO data the driver will need to perform well.
18277912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings */
18287912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jenningsstatic unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
18297912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings{
18307912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	/* iu_storage data allocated in initialize_event_pool */
18314f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	unsigned long desired_io = max_events * sizeof(union viosrp_iu);
18327912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18337912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	/* add io space for sg data */
1834004dd5e88673516a408f0e8e43edbe6a4424be2fBrian King	desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
18357912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	                     IBMVSCSI_CMDS_PER_LUN_DEFAULT);
18367912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18377912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	return desired_io;
18387912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings}
18397912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings
18400f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
18410f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18420f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	int rc;
18430f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	char *action = "reset";
18440f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18450f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (hostdata->reset_crq) {
18460f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18470f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		hostdata->reset_crq = 0;
18480f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18490f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
18500f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (!rc)
18510f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
1852201aed678482f247aa96bd8fcd9e960fefd82d59Brian King		vio_enable_interrupts(to_vio_dev(hostdata->dev));
18530f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else if (hostdata->reenable_crq) {
18540f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18550f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		action = "enable";
18560f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
18570f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		hostdata->reenable_crq = 0;
18580f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (!rc)
18590f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
18600f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else
18610f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return;
18620f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18630f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (rc) {
18640f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		atomic_set(&hostdata->request_limit, -1);
18650f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		dev_err(hostdata->dev, "error after %s\n", action);
18660f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
18670f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18680f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	scsi_unblock_requests(hostdata->host);
18690f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
18700f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18710f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
18720f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18730f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (kthread_should_stop())
18740f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18750f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	else if (hostdata->reset_crq) {
18760f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18770f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18780f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	} else if (hostdata->reenable_crq) {
18790f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		smp_rmb();
18800f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		return 1;
18810f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
18820f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18830f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	return 0;
18840f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
18850f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18860f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian Kingstatic int ibmvscsi_work(void *data)
18870f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King{
18880f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	struct ibmvscsi_host_data *hostdata = data;
18890f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	int rc;
18900f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18910f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	set_user_nice(current, -20);
18920f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18930f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	while (1) {
18940f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		rc = wait_event_interruptible(hostdata->work_wait_q,
18950f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King					      ibmvscsi_work_to_do(hostdata));
18960f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18970f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		BUG_ON(rc);
18980f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
18990f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		if (kthread_should_stop())
19000f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			break;
19010f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19020f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		ibmvscsi_do_work(hostdata);
19030f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
19040f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19050f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	return 0;
19060f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King}
19070f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19087912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings/**
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by bus code for each adapter
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ibmvscsi_host_data *hostdata;
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *host;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device *dev = &vdev->dev;
19164d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	struct srp_rport_identifiers ids;
19174d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	struct srp_rport *rport;
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long wait_switch = 0;
1919cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	int rc;
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	dev_set_drvdata(&vdev->dev, NULL);
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!host) {
19256c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't allocate host data\n");
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto scsi_host_alloc_failed;
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19294d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	host->transportt = ibmvscsi_transport_template;
19307603e02eac309626c0153ebddf277253ea7fe0e0FUJITA Tomonori	hostdata = shost_priv(host);
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(hostdata, 0x00, sizeof(*hostdata));
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&hostdata->sent);
19330f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	init_waitqueue_head(&hostdata->work_wait_q);
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hostdata->host = host;
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hostdata->dev = dev;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&hostdata->request_limit, -1);
19377912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1939126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	if (map_persist_bufs(hostdata)) {
1940126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		dev_err(&vdev->dev, "couldn't map persistent buffers\n");
1941126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King		goto persist_bufs_failed;
1942126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	}
1943126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King
19440f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
19450f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King					    "ibmvscsi", host->host_no);
19460f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19470f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	if (IS_ERR(hostdata->work_thread)) {
19480f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
19490f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King			PTR_ERR(hostdata->work_thread));
19500f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		goto init_crq_failed;
19510f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	}
19520f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King
19534f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
1954cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	if (rc != 0 && rc != H_RESOURCE) {
19556c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
19560f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King		goto kill_kthread;
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19584f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
19596c0a60ec52042ece8bf4904c91ac497188e8d70bBrian King		dev_err(&vdev->dev, "couldn't initialize event pool\n");
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto init_pool_failed;
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_lun = 8;
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_id = max_id;
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->max_channel = max_channel;
1966fbc56f0801f58041a4372a030933bac076b46aadBrian King	host->max_cmd_len = 16;
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (scsi_add_host(hostdata->host, hostdata->dev))
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto add_host_failed;
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19714d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	/* we don't have a proper target_port_id so let's use the fake one */
19724d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	memcpy(ids.port_id, hostdata->madapter_info.partition_name,
19734d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	       sizeof(ids.port_id));
1974aebd5e476ecc8ceb53577b20f2a352ff4ceffd8dFUJITA Tomonori	ids.roles = SRP_RPORT_ROLE_TARGET;
19754d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	rport = srp_rport_add(host, &ids);
19764d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (IS_ERR(rport))
19774d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		goto add_srp_port_failed;
19784d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Try to send an initialization message.  Note that this is allowed
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to fail if the other end is not acive.  In that case we don't
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * want to scan
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1983d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
1984cefbda2d6cd9bf78a93768130729a6d142588d67Dave C Boutcher	    || rc == H_RESOURCE) {
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Wait around max init_timeout secs for the adapter to finish
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * initializing. When we are done initializing, we will have a
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * valid request_limit.  We don't want Linux scanning before
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we are ready.
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (wait_switch = jiffies + (init_timeout * HZ);
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     time_before(jiffies, wait_switch) &&
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     atomic_read(&hostdata->request_limit) < 2;) {
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			msleep(10);
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* if we now have a valid request_limit, initiate a scan */
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&hostdata->request_limit) > 0)
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scsi_scan_host(host);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2003559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	dev_set_drvdata(&vdev->dev, hostdata);
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20064d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori      add_srp_port_failed:
20074d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	scsi_remove_host(hostdata->host);
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      add_host_failed:
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_event_pool(&hostdata->pool, hostdata);
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      init_pool_failed:
20114f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
20120f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King      kill_kthread:
20130f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King      kthread_stop(hostdata->work_thread);
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      init_crq_failed:
2015126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unmap_persist_bufs(hostdata);
2016126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King      persist_bufs_failed:
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host_put(host);
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      scsi_host_alloc_failed:
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ibmvscsi_remove(struct vio_dev *vdev)
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2024559fde706873256903155b3a62b05d0f52d62ab9Greg Kroah-Hartman	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
2025126c5cc37e682e7c5ae96754994b1cb50c2d0cb5Brian King	unmap_persist_bufs(hostdata);
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_event_pool(&hostdata->pool, hostdata);
2027d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
20284f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King					max_events);
20294d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20300f33ece5bc3d5a9567b65cfbc736e8f206ecfc7bBrian King	kthread_stop(hostdata->work_thread);
20314d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	srp_remove_host(hostdata->host);
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_remove_host(hostdata->host);
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host_put(hostdata->host);
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
203964355b929dec0cb6271e4ac7834c9cf262961e40Brian King * ibmvscsi_resume: Resume from suspend
204064355b929dec0cb6271e4ac7834c9cf262961e40Brian King * @dev:	device struct
204164355b929dec0cb6271e4ac7834c9cf262961e40Brian King *
204264355b929dec0cb6271e4ac7834c9cf262961e40Brian King * We may have lost an interrupt across suspend/resume, so kick the
204364355b929dec0cb6271e4ac7834c9cf262961e40Brian King * interrupt handler
204464355b929dec0cb6271e4ac7834c9cf262961e40Brian King */
204564355b929dec0cb6271e4ac7834c9cf262961e40Brian Kingstatic int ibmvscsi_resume(struct device *dev)
204664355b929dec0cb6271e4ac7834c9cf262961e40Brian King{
204764355b929dec0cb6271e4ac7834c9cf262961e40Brian King	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
204864355b929dec0cb6271e4ac7834c9cf262961e40Brian King	return ibmvscsi_ops->resume(hostdata);
204964355b929dec0cb6271e4ac7834c9cf262961e40Brian King}
205064355b929dec0cb6271e4ac7834c9cf262961e40Brian King
205164355b929dec0cb6271e4ac7834c9cf262961e40Brian King/**
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * support.
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{"vscsi", "IBM,v-scsi"},
2057fb120da678c517f72d4b39932062c2191827b331Stephen Rothwell	{ "", "" }
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
2060915124d8114ec8c3825b10a39151bf9e851593bbStephen Rothwell
206164355b929dec0cb6271e4ac7834c9cf262961e40Brian Kingstatic struct dev_pm_ops ibmvscsi_pm_ops = {
206264355b929dec0cb6271e4ac7834c9cf262961e40Brian King	.resume = ibmvscsi_resume
206364355b929dec0cb6271e4ac7834c9cf262961e40Brian King};
206464355b929dec0cb6271e4ac7834c9cf262961e40Brian King
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct vio_driver ibmvscsi_driver = {
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table = ibmvscsi_device_table,
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe = ibmvscsi_probe,
20686fdf5392caa4c3cba65add0a4beec9f5eb96b723Stephen Rothwell	.remove = ibmvscsi_remove,
20697912a0ac5907df1f8b214b3ca15ccf96129daae0Robert Jennings	.get_desired_dma = ibmvscsi_get_desired_dma,
20706fdf5392caa4c3cba65add0a4beec9f5eb96b723Stephen Rothwell	.driver = {
20716fdf5392caa4c3cba65add0a4beec9f5eb96b723Stephen Rothwell		.name = "ibmvscsi",
2072915124d8114ec8c3825b10a39151bf9e851593bbStephen Rothwell		.owner = THIS_MODULE,
207364355b929dec0cb6271e4ac7834c9cf262961e40Brian King		.pm = &ibmvscsi_pm_ops,
20746fdf5392caa4c3cba65add0a4beec9f5eb96b723Stephen Rothwell	}
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20774d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonoristatic struct srp_function_template ibmvscsi_transport_functions = {
20784d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori};
20794d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init ibmvscsi_module_init(void)
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20824d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	int ret;
20834d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
20844f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	/* Ensure we have two requests to do error recovery */
20854f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	driver_template.can_queue = max_requests;
20864f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King	max_events = max_requests + 2;
20874f10aae0d1a285df6b16bf6ca5abd366140fd371Brian King
2088d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	if (firmware_has_feature(FW_FEATURE_ISERIES))
2089d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse		ibmvscsi_ops = &iseriesvscsi_ops;
2090d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	else if (firmware_has_feature(FW_FEATURE_VIO))
2091d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse		ibmvscsi_ops = &rpavscsi_ops;
2092d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse	else
2093d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse		return -ENODEV;
2094d3849d512fb0ca1e369e3efcaec910a949f55f62David Woodhouse
20954d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	ibmvscsi_transport_template =
20964d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		srp_attach_transport(&ibmvscsi_transport_functions);
20974d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (!ibmvscsi_transport_template)
20984d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		return -ENOMEM;
20994d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori
21004d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	ret = vio_register_driver(&ibmvscsi_driver);
21014d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	if (ret)
21024d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori		srp_release_transport(ibmvscsi_transport_template);
21034d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	return ret;
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit ibmvscsi_module_exit(void)
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vio_unregister_driver(&ibmvscsi_driver);
21094d68041907b150b07640b607c6c626391cf3fe8bFUJITA Tomonori	srp_release_transport(ibmvscsi_transport_template);
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ibmvscsi_module_init);
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ibmvscsi_module_exit);
2114