zfcp_fsf.c revision 8a36e4532ea10471f0a8605207d071361d7be2c3
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/s390/scsi/zfcp_fsf.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FCP adapter driver for IBM eServer zSeries
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright IBM Corp. 2002, 2004
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author(s): Martin Peschke <mpeschke@de.ibm.com>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Raimund Schroeder <raimund.schroeder@de.ibm.com>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Aron Zeh
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Wolfgang Taphorn
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Stefan Bader <stefan.bader@de.ibm.com>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Heiko Carstens <heiko.carstens@de.ibm.com>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Andreas Herrmann <aherrman@de.ibm.com>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Volker Sameske <sameske@de.ibm.com>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2, or (at your option)
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any later version.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZFCP_FSF_C_REVISION "$Revision: 1.92 $"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zfcp_ext.h"
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *);
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_task_management_handler(
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zfcp_fsf_req_sbal_check(
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *, struct zfcp_qdio_queue *, int);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zfcp_use_one_sbal(
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scatterlist *, int, struct scatterlist *, int);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* association between FSF command and FSF QTCB type */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 fsf_qtcb_type[] = {
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char zfcp_act_subtable_type[5][8] = {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"unknown", "OS", "WWPN", "DID", "LUN"
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************/
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*************** FSF related Functions  *************************/
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************/
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_alloc
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Obtains an fsf_req and potentially a qtcb (for all but
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              unsolicited requests) via helper functions
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              Does some initial fsf request set-up.
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	pointer to allocated fsf_req if successfull
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL otherwise
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:       none
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct zfcp_fsf_req *
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t size;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *ptr;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req_flags & ZFCP_REQ_NO_QTCB)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = sizeof(struct zfcp_fsf_req);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = sizeof(struct zfcp_fsf_req_pool_element);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(pool != NULL))
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr = mempool_alloc(pool, GFP_ATOMIC);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr = kmalloc(size, GFP_ATOMIC);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(NULL == ptr))
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ptr, 0, size);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req_flags & ZFCP_REQ_NO_QTCB) {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = (struct zfcp_fsf_req *) ptr;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb =
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->pool = pool;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_free
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Frees the memory of an fsf_req (and potentially a qtcb) or
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              returns it into the pool via helper functions.
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     sod all
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:       none
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1511db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmannvoid
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->pool != NULL))
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_free(fsf_req, fsf_req->pool);
1561db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	else
1571db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		kfree(fsf_req);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note: qdio queues shall be down (no ongoing inbound processing)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req, *tmp;
1731db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	unsigned long flags;
1741db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	LIST_HEAD(remove_queue);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
1771db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	list_splice_init(&adapter->fsf_req_list_head, &remove_queue);
1781db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	atomic_set(&adapter->fsf_reqs_active, 0);
1791db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {
1821db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		list_del(&fsf_req->list);
1831db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		zfcp_fsf_req_dismiss(fsf_req);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	return 0;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_dismiss(struct zfcp_fsf_req *fsf_req)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_complete(fsf_req);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_complete
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	Updates active counts and timers for openfcp-reqs
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              May cleanup request after req_eval returns
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	0 - success
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		!0 - failure
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * context:
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cleanup;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Status read response received\n");
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Note: all cleanup handling is done in the callchain of
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the function call-chain below.
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_status_read_handler(fsf_req);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_protstatus_eval(fsf_req);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * fsf_req may be deleted due to waking up functions, so
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * cleanup is saved here and used later
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cleanup = 1;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cleanup = 0;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* cleanup request if requested by initiator */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(cleanup)) {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * lock must not be held here since it will be
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * grabed by the called routine, too
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2491db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		zfcp_fsf_req_free(fsf_req);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* notify initiator waiting for the requests completion */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: Race! We must not access fsf_req here as it might have been
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * flag. It's an improbable case. But, we have the same paranoia for
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the cleanup flag already.
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Might better be handled using complete()?
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (setting the flag and doing wakeup ought to be atomic
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  with regard to checking the flag as long as waitqueue is
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  part of the to be released structure)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up(&fsf_req->completion_wq);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_protstatus_eval
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates the QTCB of the finished FSF request
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and initiates appropriate actions
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		(usually calling FSF command specific handlers)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * context:
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
2888a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	struct fsf_qtcb *qtcb = fsf_req->qtcb;
2898a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	union fsf_prot_status_qual *prot_status_qual =
2908a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		&qtcb->prefix.prot_status_qual;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2928a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_response(fsf_req);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n",
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (unsigned long) fsf_req);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_protstatus;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* log additional information provided by FSF (if any) */
3038a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (unlikely(qtcb->header.log_length)) {
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do not trust them ;-) */
3058a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: ULP (FSF logging) log data starts "
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "beyond end of packet header. Ignored. "
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "(start=%i, size=%li)\n",
3108a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			     qtcb->header.log_start,
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     sizeof(struct fsf_qtcb));
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto forget_log;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3148a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		if ((size_t) (qtcb->header.log_start + qtcb->header.log_length)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    > sizeof(struct fsf_qtcb)) {
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"beyond end of packet header. Ignored. "
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"(start=%i, length=%i, size=%li)\n",
3198a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin					qtcb->header.log_start,
3208a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin					qtcb->header.log_length,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct fsf_qtcb));
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto forget_log;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("ULP log data: \n");
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
3268a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			      (char *) qtcb + qtcb->header.log_start,
3278a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			      qtcb->header.log_length);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds forget_log:
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF Protocol Status */
3328a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	switch (qtcb->prefix.prot_status) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_GOOD:
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_FSF_STATUS_PRESENTED:
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_QTCB_VERSION_ERROR:
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: The adapter %s contains "
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"microcode of version 0x%x, the device driver "
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports 0x%x. Aborting.\n",
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
3438a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				prot_status_qual->version_error.fsf_version,
3448a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				ZFCP_QTCB_VERSION);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_SEQ_NUMB_ERROR:
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Sequence number mismatch between "
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"driver (0x%x) and adapter %s (0x%x). "
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Restarting all operations on this adapter.\n",
3538a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				qtcb->prefix.req_seq_no,
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
3558a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				prot_status_qual->sequence_error.exp_req_seq_no);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_UNSUPP_QTCB_TYPE:
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: Packet header type used by the "
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"device driver is incompatible with "
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"that used on adapter %s. "
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter.\n",
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&(adapter->status));
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_DUPLICATE_REQUEST_ID:
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->qtcb) {
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx "
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"to the adapter %s is ambiguous. "
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"Stopping all operations on this "
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter.\n",
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					*(unsigned long long *)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(&fsf_req->qtcb->bottom.support.
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 req_handle),
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The request identifier %p "
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"to the adapter %s is ambiguous. "
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"Stopping all operations on this "
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter. "
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"(bug: got this for an unsolicited "
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"status read request)\n",
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req,
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_LINK_DOWN:
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * 'test and set' is not atomic here -
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's ok as long as calls to our response queue handler
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (and thus execution of this code here) are serialized
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * by the qdio module
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      &adapter->status)) {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (fsf_req->qtcb->prefix.prot_status_qual.
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				locallink_error.code) {
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_PSQ_LINK_NOLIGHT:
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("The local link to adapter %s "
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "is down (no light detected).\n",
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      zfcp_get_busid_by_adapter(
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      adapter));
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_PSQ_LINK_WRAPPLUG:
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("The local link to adapter %s "
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "is down (wrap plug detected).\n",
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      zfcp_get_busid_by_adapter(
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      adapter));
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_PSQ_LINK_NOFCP:
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("The local link to adapter %s "
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "is down (adjacent node on "
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "link does not support FCP).\n",
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      zfcp_get_busid_by_adapter(
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      adapter));
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("The local link to adapter %s "
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "is down "
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "(warning: unknown reason "
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      "code).\n",
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      zfcp_get_busid_by_adapter(
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      adapter));
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Due to the 'erp failed' flag the adapter won't
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * be recovered but will be just set to 'blocked'
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * state. All subordinary devices will have state
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * 'blocked' and 'erp failed', too.
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Thus the adapter is still able to provide
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * 'link up' status without being flooded with
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * requests.
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * (note: even 'close port' is not permitted)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("Stopping all operations for adapter "
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "%s.\n",
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_STATUS_COMMON_ERP_FAILED,
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&adapter->status);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(adapter, 0);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_REEST_QUEUE:
4638a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter with "
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%s was re-plugged. "
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "Re-starting operations on this adapter.\n",
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* All ports should be marked as ready to run again */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_adapter_status(adapter,
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_STATUS_COMMON_RUNNING,
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_SET);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter,
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					| ZFCP_STATUS_COMMON_ERP_FAILED);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_ERROR_STATE:
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: The adapter %s "
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"has entered the error state. "
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Restarting all operations on this "
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter.\n",
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Transfer protocol status information "
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"provided by the adapter %s "
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is not compatible with the device driver. "
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. "
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x).\n",
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
4958a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				qtcb->prefix.prot_status);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_protstatus:
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * always call specific handlers to give them a chance to do
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * something meaningful even in error cases
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_fsfstatus_eval(fsf_req);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_fsfstatus_eval
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FSF status of completed FSF request
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and acts accordingly
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF Status */
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_COMMAND:
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is "
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not known by the adapter %s "
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. "
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x).\n",
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter),
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_command);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_RSP_AVAILABLE:
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("FCP Sense data will be presented to the "
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "SCSI stack.\n");
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_fsfstatus_qual_eval(fsf_req);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * always call specific handlers to give them a chance to do
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * something meaningful even in error cases
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_dispatch(fsf_req);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_fsfstatus_qual_eval
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FSF status-qualifier of completed FSF request
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and acts accordingly
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_FCP_RSP_AVAILABLE:
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_RETRY_IF_POSSIBLE:
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The SCSI-stack may now issue retries or escalate */
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_COMMAND_ABORTED:
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Carry the aborted state on to upper layer */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_NO_RECOM:
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"problem on the adapter %s "
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. ",
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter));
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_ULP_PROGRAMMING_ERROR:
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer "
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(adapter %s)\n",
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter));
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_NO_RETRY_POSSIBLE:
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* dealt with in the respective functions */
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Additional status info could "
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not be interpreted properly.\n");
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_dispatch
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	calls the appropriate command specific handler
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_erp_action *erp_action = fsf_req->erp_action;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->fsf_command) {
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_FCP_CMND:
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_fcp_command_handler(fsf_req);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_ABORT_FCP_CMND:
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_abort_fcp_command_handler(fsf_req);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_SEND_GENERIC:
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_ct_handler(fsf_req);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_OPEN_PORT_WITH_DID:
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_open_port_handler(fsf_req);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_OPEN_LUN:
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_open_unit_handler(fsf_req);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_LUN:
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_unit_handler(fsf_req);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_PORT:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_port_handler(fsf_req);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_physical_port_handler(fsf_req);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_exchange_config_data_handler(fsf_req);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_EXCHANGE_PORT_DATA:
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_exchange_port_data_handler(fsf_req);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_SEND_ELS:
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_els_handler(fsf_req);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_control_file_handler(fsf_req);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_UPLOAD_CONTROL_FILE:
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_control_file_handler(fsf_req);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is "
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not supported by the adapter %s\n",
6898a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Command issued by the device driver differs "
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "from the command returned by the adapter %s "
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "(debug info 0x%x, 0x%x).\n",
6958a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			     zfcp_get_busid_by_adapter(adapter),
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->fsf_command,
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->qtcb->header.fsf_command);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!erp_action)
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_erp_async_handler(erp_action, 0);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_status_read
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	initiates a Status Read command at the specified adapter
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     req_flags | ZFCP_REQ_NO_QTCB,
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_status_read,
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create unsolicited status "
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "buffer for adapter %s.\n",
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_create;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        fsf_req->sbale_curr = 2;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status_buffer =
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!status_buffer) {
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: could not get some buffer\n");
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_buf;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer));
748059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) status_buffer;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* insert pointer to respective buffer */
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_curr(fsf_req);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale->addr = (void *) status_buffer;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale->length = sizeof(struct fsf_status_read_buffer);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, NULL);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status "
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "environment.\n");
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_send;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n",
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter));
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_send:
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mempool_free(status_buffer, adapter->pool.data_status_read);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_buf:
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_create:
7738a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
787059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock_irqsave(&zfcp_data.config_lock, flags);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(port, &adapter->port_list_head, list)
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK))
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"nonexisting port with d_id 0x%08x on "
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s. Ignored.\n",
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->d_id & ZFCP_DID_MASK,
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (status_buffer->status_subtype) {
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 3, "unsol_pc_phys:");
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(port, 0);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SUB_ERROR_PORT:
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "unsol_pc_err:");
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_shutdown(port, 0);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "unsol_unk_sub:");
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&status_buffer->status_subtype, sizeof (u32));
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"for a reopen indication on port with "
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"d_id 0x%08x on the adapter %s. "
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Ignored. (debug info 0x%x)\n",
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->d_id,
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->status_subtype);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_status_read_handler
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open Port command
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer =
846059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		(struct fsf_status_read_buffer *) fsf_req->data;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
8498a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_free(status_buffer, adapter->pool.data_status_read);
8511db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		zfcp_fsf_req_free(fsf_req);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8558a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer);
8568a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (status_buffer->status_type) {
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_PORT_CLOSED:
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_status_read_port_closed(fsf_req);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_INCOMING_ELS:
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_incoming_els(fsf_req);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n",
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Bit error threshold data received:\n");
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) status_buffer,
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (struct fsf_status_read_buffer));
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_LINK_DOWN:
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "unsol_link_down:");
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Local link to adapter %s is down\n",
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&adapter->status);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_failed(adapter);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_LINK_UP:
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "unsol_link_up:");
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Local link to adapter %s was replugged. "
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "Restarting operations on this adapter\n",
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* All ports should be marked as ready to run again */
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_adapter_status(adapter,
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_STATUS_COMMON_RUNNING,
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_SET);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter,
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					| ZFCP_STATUS_COMMON_ERP_FAILED);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_CFDC_UPDATED:
9038a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n",
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_access_changed(adapter);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_CFDC_HARDENED:
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status_buffer->status_subtype) {
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE:
9118a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n",
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2:
9158a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied "
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "to the secondary SE\n",
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
9208a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n",
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9268a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown "
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"type was received (debug info 0x%x)\n",
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->status_type);
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n",
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       status_buffer);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) status_buffer,
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (struct fsf_status_read_buffer));
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mempool_free(status_buffer, adapter->pool.data_status_read);
9371db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	zfcp_fsf_req_free(fsf_req);
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * recycle buffer and start new request repeat until outbound
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * queue is empty or adapter shutdown is requested
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FIXME(qdio):
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we may wait in the req_create for 5s during shutdown, so
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * qdio_cleanup will have to wait at least that long before returning
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with failure to allow us a proper cleanup under all circumstances
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FIXME:
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * allocation failure possible? (Is this code needed?)
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_status_read(adapter, 0);
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Failed to create unsolicited status read "
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request for the adapter %s.\n",
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* temporary fix to avoid status read buffer shortage */
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->status_read_failed++;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed)
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    < ZFCP_STATUS_READ_FAILED_THRESHOLD) {
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("restart adapter %s due to status read "
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "buffer shortage\n",
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(adapter, 0);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_abort_fcp_command
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	tells FSF to abort a running SCSI command
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL - request could not be initiated
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design): should be watched by a timeout !!!
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design) shouldn't this be modified to return an int
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *               also...don't know how though
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct zfcp_fsf_req *
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_abort_fcp_command(unsigned long old_req_id,
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct zfcp_adapter *adapter,
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct zfcp_unit *unit, int req_flags)
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     req_flags, adapter->pool.fsf_req_abort,
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Failed to create an abort command "
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request for lun 0x%016Lx on port 0x%016Lx "
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s.\n",
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handle of request which should be aborted */
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_start_scsi_er_timer(adapter);
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, NULL);
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer(&adapter->scsi_er_timer);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Failed to send abort command request "
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, unit->fcp_lun);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter%s, port d_id=0x%08x, "
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "unit x%016Lx, old_req_id=0x%lx)\n",
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->d_id,
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun, old_req_id);
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_abort_fcp_command_handler
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Abort FCP Command request
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
1057059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char status_qual =
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    new_fsf_req->qtcb->header.fsf_status_qual.word[0];
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&new_fsf_req->adapter->scsi_er_timer);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1068059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) new_fsf_req->data;
1069059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (new_fsf_req->qtcb->header.fsf_status) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status_qual >> 4 != status_qual % 0xf) {
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv0");
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a port
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different). This is
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * fine.
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("Temporary port identifier 0x%x for "
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "port 0x%016Lx on adapter %s invalid. "
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "This may happen occasionally.\n",
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->handle,
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->wwpn,
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_unit(unit));
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("status qualifier:\n");
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv1");
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(unit->port->adapter, 0);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status_qual >> 4 != status_qual % 0xf) {
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 2 */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv0");
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a unit
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different).
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * This is fine.
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("Warning: Temporary LUN identifier 0x%x of LUN "
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "0x%016Lx on port 0x%016Lx on adapter %s is "
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "invalid. This may happen in rare cases. "
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "Trying to re-establish link.\n",
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->handle,
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->fcp_lun,
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->port->wwpn,
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     zfcp_get_busid_by_unit(unit));
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG("Status qualifier data:\n");
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv1");
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_reopen(unit->port, 0);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_no_exist");
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to "
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "be reopened\n", unit->port->wwpn,
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 2,
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_pboxed");
1148d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO(
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "unit 0x%016Lx on port 0x%016Lx on adapter %s needs "
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "to be reopened\n",
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        unit->fcp_lun, unit->port->wwpn,
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        zfcp_get_busid_by_unit(unit));
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
1160d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        | ZFCP_STATUS_FSFREQ_RETRY;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
117065a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* SCSI stack will escalate */
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     new_fsf_req->qtcb->header.fsf_status_qual.word[0]);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(new_fsf_req->adapter->erp_dbf, 0,
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&new_fsf_req->qtcb->header.
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_status_qual.word[0], sizeof (u32));
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_fsf_req->qtcb->header.fsf_status);
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_inval:");
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(new_fsf_req->adapter->erp_dbf, 0,
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&new_fsf_req->qtcb->header.fsf_status,
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	one SBALE
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Two scatter-gather lists are passed, one for the reqeust and one for the
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * response.
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_use_one_sbal(struct scatterlist *req, int req_count,
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  struct scatterlist *resp, int resp_count)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ((req_count == 1) &&
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(resp_count == 1) &&
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&req[0]) &
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 ((unsigned long) (zfcp_sg_to_address(&req[0]) +
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   req[0].length - 1) & PAGE_MASK)) &&
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&resp[0]) &
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                 ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   resp[0].length - 1) & PAGE_MASK)));
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the request
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool: pointer to memory pool, if non-null this pool is used to allocate
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	a struct zfcp_fsf_req
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @erp_action: pointer to erp_action, if non-null the Generic Service request
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	is sent within error recovery
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct zfcp_erp_action *erp_action)
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_fsf_req *fsf_req;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        unsigned long lock_flags;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = ct->port;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = port->adapter;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  pool, &lock_flags, &fsf_req);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for "
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter: %s\n",
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (erp_action != NULL) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                erp_action->fsf_req = fsf_req;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->erp_action = erp_action;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (zfcp_use_one_sbal(ct->req, ct->req_count,
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              ct->resp, ct->resp_count)){
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* both request buffer and response buffer
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   fit into one sbale each */
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].length = ct->req[0].length;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].length = ct->resp[0].length;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else if (adapter->supported_features &
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* try to use chained SBALs */
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->req, ct->req_count,
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->resp, ct->resp_count,
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else {
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* reject send generic request */
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"error: microcode does not support chained SBALs,"
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "CT request too big (adapter %s)\n",
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = -EOPNOTSUPP;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_send;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* settings in QTCB */
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = port->handle;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.timeout = ct->timeout;
1334059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann        fsf_req->data = (unsigned long) ct;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13368a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_san_dbf_event_ct_request(fsf_req);
13378a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = zfcp_fsf_req_send(fsf_req, ct->timer);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: initiation of CT request failed "
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(adapter %s, port 0x%016Lx)\n",
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter), port->wwpn);
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n",
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter), port->wwpn);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (erp_action != NULL) {
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                erp_action->fsf_req = NULL;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        write_unlock_irqrestore(&adapter->request_queue.queue_lock,
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct_handler - handler for Generic Service requests
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1367059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the Generic Service request is passed using
1368059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_ct.
1369059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the CT request is called which is
1370059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_ct *send_ct;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
1384059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_ct = (struct zfcp_send_ct *) fsf_req->data;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = send_ct->port;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
13968a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_ct_response(fsf_req);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                retval = 0;
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (adapter->fc_service_class <= 3) {
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("error: adapter %s does not support fc "
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "class %d.\n",
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_port(port),
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      adapter->fc_service_class);
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: The fibre channel class at the "
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "adapter %s is invalid. "
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "(debug info %d)\n",
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_port(port),
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      adapter->fc_service_class);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* reopening link to port */
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_test_link(port);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                default:
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x "
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "arrived.\n",
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send generic service "
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"command (adapter %s, port d_id=0x%08x)\n",
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_port(port), port->d_id);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GENERIC_COMMAND_REJECTED:
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("generic service command rejected "
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port d_id=0x%08x)\n",
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej");
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_HANDLE_NOT_VALID:
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port "
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "0x%016Lx on adapter %s invalid. This may "
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "happen occasionally.\n", port->handle,
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn, zfcp_get_busid_by_port(port));
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv");
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("port needs to be reopened "
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port d_id=0x%08x)\n",
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
1493d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* following states should never occure, all cases avoided
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   in zfcp_fsf_send_ct - but who knows ... */
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("payload size mismatch (adapter: %s, "
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d, resp_buf_length=%d)\n",
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("request size too large (adapter: %s, "
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d)\n",
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length);
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("response size too large (adapter: %s, "
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->resp_buf_length);
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       default:
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n", header->fsf_status);
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:");
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ct->status = retval;
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (send_ct->handler != NULL)
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @els: pointer to struct zfcp_send_els which contains all needed data for
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the command.
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_els(struct zfcp_send_els *els)
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fc_id_t d_id;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = els->d_id;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = els->adapter;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_REQ_AUTO_CLEANUP,
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  NULL, &lock_flags, &fsf_req);
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: creation of ELS request failed "
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port d_id: 0x%08x)\n",
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              zfcp_get_busid_by_adapter(adapter), d_id);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_req;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (zfcp_use_one_sbal(els->req, els->req_count,
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              els->resp, els->resp_count)){
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* both request buffer and response buffer
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   fit into one sbale each */
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].addr = zfcp_sg_to_address(&els->req[0]);
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].length = els->req[0].length;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].length = els->resp[0].length;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else if (adapter->supported_features &
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* try to use chained SBALs */
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                els->req, els->req_count,
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of ELS request failed "
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "(adapter %s, port d_id: 0x%08x)\n",
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter), d_id);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0) {
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        } else {
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        }
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                els->resp, els->resp_count,
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of ELS request failed "
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "(adapter %s, port d_id: 0x%08x)\n",
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter), d_id);
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0) {
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        } else {
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        }
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else {
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* reject request */
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              ", ELS request too big (adapter %s, "
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port d_id: 0x%08x)\n",
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter), d_id);
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = -EOPNOTSUPP;
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_send;
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* settings in QTCB */
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.d_id = d_id;
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
1637059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) els;
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16418a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_san_dbf_event_els_request(fsf_req);
16428a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = zfcp_fsf_req_send(fsf_req, els->timer);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(adapter %s, port d_id: 0x%08x)\n",
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter), d_id);
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ret;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els_handler - handler for ELS commands
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1671059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the ELS command is passed using
1672059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_els.
1673059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the ELS command is called which is
1674059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
168064b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann	fc_id_t d_id;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_els *send_els;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1687059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_els = (struct zfcp_send_els *) fsf_req->data;
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = send_els->adapter;
168964b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann	port = send_els->port;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = send_els->d_id;
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
17008a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_els_response(fsf_req);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (adapter->fc_service_class <= 3) {
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("error: adapter %s does "
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "not support fibrechannel class %d.\n",
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter),
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      adapter->fc_service_class);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: The fibrechannel class at "
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "adapter %s is invalid. "
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "(debug info %d)\n",
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter),
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      adapter->fc_service_class);
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
172764b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
172864b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval =
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      (struct zfcp_ls_rjt_par *)
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      &header->fsf_status_qual.word[2]);
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry");
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n",
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(char*)header->fsf_status_qual.word, 16);
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("ELS has been rejected because command filter "
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "prohibited sending "
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter: %s, port d_id: 0x%08x)\n",
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter), d_id);
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"ELS request size and ELS response size must be either "
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"both 0, or both greater than 0 "
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n",
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length,
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS request buffer, "
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS request data "
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d)\n",
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length);
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS response buffer, "
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS response data "
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, resp_buf_length=%d)\n",
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, avoided in zfcp_fsf_send_els */
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(adapter %s, port d_id=0x%08x)\n",
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter), d_id);
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (port != NULL)
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_access_denied(port);
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown FSF Status was presented "
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, fsf_status=0x%08x)\n",
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status);
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval");
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_els->status = retval;
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (send_els->handler != 0)
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL - request could not be initiated
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_EXCHANGE_CONFIG_DATA,
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_REQ_AUTO_CLEANUP,
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &(erp_action->fsf_req));
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create exchange configuration "
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "data request for adapter %s.\n",
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    erp_action->fsf_req->sbal_curr, 0);
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->bottom.config.feature_selection =
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING);
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("error: Could not send exchange configuration data "
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "command on the adapter %s\n",
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     zfcp_get_busid_by_adapter(erp_action->adapter));
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("exchange configuration data request initiated "
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s)\n",
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter));
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_config_evaluate
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: fsf_req which belongs to xchg config data request
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1)
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns: -EIO on error, 0 otherwise
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.config;
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n",
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       bottom->low_qtcb_version, bottom->high_qtcb_version);
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter->fsf_lic_version = bottom->lic_version;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter->supported_features = bottom->supported_features;
19226f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwpn = 0;
19236f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwnn = 0;
19246f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_d_id = 0;
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xchg_ok) {
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->wwnn = bottom->nport_serv_param.wwnn;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->wwpn = bottom->nport_serv_param.wwpn;
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->s_id = bottom->s_id & ZFCP_DID_MASK;
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->fc_topology = bottom->fc_topology;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->fc_link_speed = bottom->fc_link_speed;
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = bottom->adapter_type;
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->wwnn = 0;
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->wwpn = 0;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->s_id = 0;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->fc_topology = 0;
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->fc_link_speed = 0;
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = 0;
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19426f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	if (adapter->fc_topology == FSF_TOPO_P2P) {
19436f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
19446f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
19456f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
19466f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	}
19476f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hardware_version = bottom->hardware_version;
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(adapter->serial_number, bottom->serial_number, 17);
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		EBCASC(adapter->serial_number, sizeof(adapter->serial_number));
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19546f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "WWNN 0x%016Lx, "
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "WWPN 0x%016Lx, "
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "S_ID 0x%08x,\n"
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "adapter version 0x%x, "
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "LIC version 0x%x, "
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "FC link speed %d Gb/s\n",
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      zfcp_get_busid_by_adapter(adapter),
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      adapter->wwnn,
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      adapter->wwpn,
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (unsigned int) adapter->s_id,
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      adapter->hydra_version,
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      adapter->fsf_lic_version,
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      adapter->fc_link_speed);
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports newer control block "
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions in comparison to this device "
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"driver (try updated device driver)\n",
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "low_qtcb_ver");
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports older control block "
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions than this device driver uses"
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(consider a microcode upgrade)\n",
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "high_qtcb_ver");
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19883859f6a248cbdfbe7b41663f3a2b51f48e30b281Andreas Herrmann	zfcp_set_fc_host_attrs(adapter);
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_exchange_config_data_handler
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Exchange Configuration Data command
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (adapter->fc_topology) {
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_TOPO_P2P:
20166f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
20176f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"configuration detected at adapter %s\n"
20186f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"Peer WWNN 0x%016llx, "
20196f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer WWPN 0x%016llx, "
20206f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer d_id 0x%06x\n",
20216f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter),
20226f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwnn,
20236f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwpn,
20246f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_d_id);
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "top-p-to-p");
20276f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			break;
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_TOPO_AL:
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"topology detected at adapter %s "
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"unsupported, shutting down adapter\n",
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "top-al");
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_TOPO_FABRIC:
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("Switched fabric fibrechannel "
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "network detected at adapter %s.\n",
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"reported by the exchange "
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"configuration command for "
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"the adapter %s is not "
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"of a type known to the zfcp "
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"driver, shutting down adapter\n",
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
20506f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			adapter->fc_topology = FSF_TOPO_ERROR;
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "unknown-topo");
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bottom = &fsf_req->qtcb->bottom.config;
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"allowed by the adapter %s "
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is lower than the minimum "
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"required by the driver (%ld bytes).\n",
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bottom->max_qtcb_size,
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter),
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct fsf_qtcb));
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "qtcb-size");
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_event(fsf_req->adapter->erp_dbf, 0,
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    &bottom->max_qtcb_size, sizeof (u32));
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&adapter->status);
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "xchg-inco");
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Local link to adapter %s is down\n",
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&adapter->status);
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_failed(adapter);
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_event(fsf_req->adapter->erp_dbf, 0,
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &fsf_req->qtcb->header.fsf_status, sizeof (u32));
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: for which port data is requested
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: response to exchange port data request
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct fsf_qtcb_bottom_port *data)
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_fsf_req *fsf_req;
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list *timer;
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: exchange port data "
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "command not supported by adapter %s\n",
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EOPNOTSUPP;
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!timer)
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                     0, 0, &lock_flags, &fsf_req);
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "exchange port data request for"
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "the adapter %s.\n",
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2137059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) data;
2138059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(timer);
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->function = zfcp_fsf_request_timeout_handler;
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->data = (unsigned long) adapter;
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, timer);
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an exchange port data "
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "command on the adapter %s\n",
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Exchange Port Data request initiated (adapter %s)\n",
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter));
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(fsf_req->completion_wq,
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(timer);
21681db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	zfcp_fsf_req_free(fsf_req);
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(timer);
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_port *bottom;
2183059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct fsf_qtcb_bottom_port *data;
2184059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
2185059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bottom = &fsf_req->qtcb->bottom.port;
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                memcpy(data, bottom, sizeof(*data));
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        default:
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng");
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                debug_event(fsf_req->adapter->erp_dbf, 0,
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &fsf_req->qtcb->header.fsf_status, sizeof(u32));
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL - request could not be initiated
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_PORT_WITH_DID,
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &(erp_action->fsf_req));
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open port request "
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    erp_action->fsf_req->sbal_curr, 0);
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
2240059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	erp_action->fsf_req->data = (unsigned long) erp_action->port;
22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send open port request for "
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("open port request initiated "
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s,  port 0x%016Lx)\n",
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port_handler
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open Port command
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s "
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is already open.\n",
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_popen");
22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This is a bug, however operation should continue normally
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * if it is simply ignored
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx "
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"on adapter %s\n",
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The FSF adapter is out of resources. "
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The remote port 0x%016Lx on adapter %s "
23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "could not be opened. Disabling it.\n",
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_ports");
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_failed(port);
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("The remote port 0x%016Lx on "
23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s could not be opened. "
23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"Disabling it.\n",
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwpn,
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_port(port));
23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "fsf_sq_no_retry");
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_failed(port);
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0],
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save port handle assigned by FSF */
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s "
23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "was opened, it's port handle is 0x%x\n",
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port),
23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle);
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark port as open */
23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
2386d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
2387d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
2388d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (fsf_req->qtcb->bottom.support.els1_length <
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ((((unsigned long) &plogi->serv_param.wwpn) -
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      ((unsigned long) plogi)) + sizeof (u64))) {
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO(
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"warning: insufficient length of "
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"PLOGI payload (%i)\n",
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req->qtcb->bottom.support.els1_length);
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debug_text_event(fsf_req->adapter->erp_dbf, 0,
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 "fsf_s_short_plogi:");
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* skip sanity check and assume wwpn is ok */
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (plogi->serv_param.wwpn != port->wwpn) {
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_LOG_INFO("warning: d_id of port "
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "0x%016Lx changed during "
24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "open\n", port->wwpn);
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debug_text_event(
24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						fsf_req->adapter->erp_dbf, 0,
24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fsf_s_did_change:");
24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					atomic_clear_mask(
24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_STATUS_PORT_DID_DID,
24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&port->status);
24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwnn = plogi->serv_param.wwnn;
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, subtype not set in zfcp_fsf_open_port */
24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, "
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "op_subtype=0x%x)\n",
24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.support.operation_subtype);
24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port
24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close port"
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PORT,
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &(erp_action->fsf_req));
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create a close port request "
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    erp_action->fsf_req->sbal_curr, 0);
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
2494059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	erp_action->fsf_req->data = (unsigned long) erp_action->port;
24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->header.port_handle =
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    erp_action->port->handle;
24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close port request for "
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close port request initiated "
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port_handler
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Port FSF command
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2534059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may happen "
25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "occasionally.\n", port->handle,
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Note: FSF has actually closed the port in this case.
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The status code is just daft. Fingers crossed for a change
25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, "
25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "port handle 0x%x\n", port->wwpn,
25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_port_status(port,
25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port
25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close physical port"
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PHYSICAL_PORT,
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &erp_action->fsf_req);
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close physical port "
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    erp_action->fsf_req->sbal_curr, 0);
26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* mark port as being closed */
26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&erp_action->port->status);
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* save a pointer to this port */
2631059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	erp_action->fsf_req->data = (unsigned long) erp_action->port;
26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* port to be closeed */
26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->header.port_handle =
26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    erp_action->port->handle;
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send close physical port "
26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close physical port request initiated "
26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port_handler
26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Physical Port FSF command
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req)
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2675059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid"
26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port 0x%016Lx). "
26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally.\n",
26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle,
26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn);
26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot close "
27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"physical port 0x%016Lx on adapter %s\n",
27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       			ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter "
27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s needs to be reopened but it was attempted "
27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "to close it physically.\n",
27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port));
27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_pboxed");
2732d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This will now be escalated by ERP */
27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s "
27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "physically closed, port handle 0x%x\n",
27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit
27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions:	This routine does not check whether the associated
28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		remote port has already been opened. This should be
28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		done by calling routines. Otherwise some status
28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		may be presented by FSF
28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_LUN,
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &(erp_action->fsf_req));
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open unit request for "
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->port->wwpn,
28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    erp_action->fsf_req->sbal_curr, 0);
28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->header.port_handle =
28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->port->handle;
28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->unit->fcp_lun;
28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->bottom.support.option =
28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FSF_OPEN_LUN_SUPPRESS_BOXING;
28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
2839059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	erp_action->fsf_req->data = (unsigned long) erp_action->unit;
28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an open unit request "
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on the adapter %s, port 0x%016Lx for "
28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx\n",
28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun);
28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, "
28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit_handler
28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open LUN command
28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_queue_designator *queue_designator;
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 allowed, exclusive, readwrite;
28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2885059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	queue_designator = &header->fsf_status_qual.fsf_queue_designator;
28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	allowed   = bottom->lun_access_info & FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED;
28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	exclusive = bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE;
28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	readwrite = bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER;
29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x "
29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s invalid "
29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally\n",
29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_ph_nv");
29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on "
29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s twice.\n",
29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, zfcp_get_busid_by_unit(unit));
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0,
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_uopen");
29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on "
29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s\n",
29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun, unit->port->wwpn,
29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
2964d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (header->fsf_status_qual.word[0] != 0) {
29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port "
29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"with WWPN 0x%Lx "
29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"connected to the adapter %s "
29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is already in use in LPAR%d, CSS%d\n",
29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->hla,
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->cssid);
29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[4];
29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[5];
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the "
29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"remote port with WWPN 0x%Lx "
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"connected to the adapter %s "
29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"is denied (%s rule %d)\n",
29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun,
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_act_subtable_type[subtable],
29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rule);
29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2,
30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_l_sh_vio");
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The adapter ran out of resources. "
30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "There is no handle (temporary port identifier) "
30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "available for unit 0x%016Lx on port 0x%016Lx "
30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s\n",
30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1,
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_units");
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_failed(unit);
30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Re-establish link to port */
30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
303265a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 0,
30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(adapter->erp_dbf, 0,
30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save LUN handle assigned by FSF */
30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on "
30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s opened, port handle 0x%x\n",
30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as open */
30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
3074d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
3075d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
3076d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &unit->status);
30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (adapter->supported_features & FSF_FEATURE_LUN_SHARING){
30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("read-only access for unit "
30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"(adapter %s, wwpn=0x%016Lx, "
30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fcp_lun=0x%016Lx)\n",
30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun);
30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("exclusive access of read-only "
30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_failed(unit);
30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("shared access of read-write "
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		zfcp_erp_unit_failed(unit);
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_s_inval:");
31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit
31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of fsf_req - request successfully initiated
31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL -
31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions: This routine does not check whether the associated
31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              remote port/lun has already been opened. This should be
31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              done by calling routines. Otherwise some status
31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              may be presented by FSF
31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_LUN,
31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &(erp_action->fsf_req));
31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close unit request for "
31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    erp_action->fsf_req->sbal_curr, 0);
31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->header.port_handle =
31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    erp_action->port->handle;
31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
3170059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	erp_action->fsf_req->data = (unsigned long) erp_action->unit;
31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	erp_action->fsf_req->erp_action = erp_action;
31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close unit request for "
31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n",
31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(erp_action->fsf_req);
31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, "
31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit_handler
31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close LUN FSF command
32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3209059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may "
32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "happen in rare circumstances\n",
32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit "
32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Status qualifier data:\n");
32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_lhand_nv");
32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit));
32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3260d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
327165a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status_qual.word[0],
32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s "
32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "closed, port handle 0x%x\n",
32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as closed */
33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter where scsi command is issued
33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @unit: unit where command is sent to
33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @scsi_cmnd: scsi command to be sent
33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @timer: timer to be started when request is initiated
33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags for fsf_request
33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct zfcp_unit *unit,
33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct scsi_cmnd * scsi_cmnd,
33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct timer_list *timer, int req_flags)
33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sbtype;
33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int real_bytes = 0;
33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mask;
33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not create FCP command request "
33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "for unit 0x%016Lx on port 0x%016Lx on "
33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s\n",
33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter));
33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_create;
33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3358059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_get(unit);
3359059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->unit = unit;
33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate FSF request with SCSI request (for look up on abort) */
3362059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	scsi_cmnd->host_scribble = (char *) fsf_req;
3363059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
3364059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate SCSI command with FSF request */
3365059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) scsi_cmnd;
33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FSF does not define the structure of the FCP_CMND IU */
33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set depending on data direction:
33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in SBALE (SB Type)
33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in QTCB
33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in FCP_CMND IU
33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (scsi_cmnd->sc_data_direction) {
33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_NONE:
33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME(qdio):
33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * what is the correct type for commands
33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * without 'real' data buffers?
33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_FROM_DEVICE:
33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->rddata = 1;
33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_TO_DEVICE:
33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_WRITE;
33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->wddata = 1;
34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_BIDIRECTIONAL:
34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * dummy, catch this condition earlier
34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in zfcp_scsi_queuecommand
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_scsi_cmnd;
34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FC service class in QTCB (3 per default) */
34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.service_class = adapter->fc_service_class;
34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP_LUN in FCP_CMND IU in QTCB */
34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED;
34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set task attributes in FCP_CMND IU in QTCB */
34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely((scsi_cmnd->device->simple_tags) ||
34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (atomic_test_mask(mask, &unit->status))))
34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = UNTAGGED;
34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length
34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "additional FCP_CDB length is 0x%x "
34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(shifted right 2 bits)\n",
34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scsi_cmnd->cmd_len,
34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_cmnd_iu->add_fcp_cdb_length);
34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI CDB (including additional length, if any) to
34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FCP_CDB in FCP_CMND IU in QTCB
34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FCP CMND IU length in QTCB */
34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) +
34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* generate SBALEs from data buffer */
34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd);
34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(real_bytes < 0)) {
34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) {
34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG(
34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Data did not fit into available buffer(s), "
34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "waiting for more...\n");
34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: No truncation implemented but "
34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"required. Shutting down unit "
34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(adapter %s, port 0x%016Lx, "
34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx)\n",
34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun);
34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_shutdown(unit, 0);
34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_fit;
34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set length of FCP data length in FCP_CMND IU in QTCB */
34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Sending SCSI command:\n");
34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * start QDIO request for this FSF request
34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  covered by an SBALE)
34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, timer);
34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send FCP command request "
34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send_failed;
34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, "
34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun);
34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_failed:
34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_fit:
34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_scsi_cmnd:
3499059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_put(unit);
35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_cmnd->host_scribble = NULL;
35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_create:
35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_management
35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design): should be watched by a timeout!!!
35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design) shouldn't this be modified to return an int
35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *               also...don't know how though
35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct zfcp_fsf_req *
35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  struct zfcp_unit *unit,
35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  u8 tm_flags, int req_flags)
35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FCP command (task "
35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) request for adapter %s, port "
35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      " 0x%016Lx, unit 0x%016Lx.\n",
35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, unit->fcp_lun);
35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Used to decide on proper handler in the return path,
35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * could be either zfcp_fsf_send_fcp_command_task_handler or
35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * zfcp_fsf_send_fcp_command_task_management_handler */
35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * hold a pointer to the unit being target of this
35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * task management request
35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3556059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FSF related fields in QTCB */
35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.service_class = adapter->fc_service_class;
35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP related fields in FCP_CMND IU in QTCB */
35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		&(fsf_req->qtcb->bottom.io.fcp_cmnd);
35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->task_management_flags = tm_flags;
35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start QDIO request for this FSF request */
35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_start_scsi_er_timer(adapter);
35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, NULL);
35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer(&adapter->scsi_er_timer);
35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) on adapter %s, port 0x%016Lx for "
35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit LUN 0x%016Lx\n",
35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "tm_flags=0x%x)\n",
35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun,
35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       tm_flags);
35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_handler
36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Send FCP Command
36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
3622059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = (struct zfcp_unit *) fsf_req->data;
36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3624059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = fsf_req->unit;
36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* go directly to calls of special handlers */
36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid\n",
36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit "
36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Status qualifier data:\n");
36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_uhand_nv");
36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_HANDLE_MISMATCH:
36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed "
36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unexpectedly. (adapter %s, port 0x%016Lx, "
36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx)\n",
36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->handle,
36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun);
36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("status qualifier:\n");
36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_hand_mis");
36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->adapter->fc_service_class <= 3) {
36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("error: The adapter %s does "
36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"not support fibrechannel class %d.\n",
36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req->adapter->fc_service_class);
36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The fibrechannel class at "
36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s is invalid. "
36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"(debug info %d)\n",
36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req->adapter->fc_service_class);
36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_class_nsup");
37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCPLUN_NOT_VALID:
37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on "
37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s does not have correct unit "
37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"handle 0x%x\n",
37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->handle);
37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_fcp_lun_nv");
37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to "
37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx on port 0x%016Lx on "
37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s\n",	unit->fcp_lun, unit->port->wwpn,
37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_DIRECTION_INDICATOR_NOT_VALID:
37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("bug: Invalid data direction given for unit "
37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s "
37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(debug info %d)\n",
37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.io.data_direction);
37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_dir_ind_nv");
37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CMND_LENGTH_NOT_VALID:
37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL
37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("bug: An invalid control-data-block length field "
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "was found in a command for unit 0x%016Lx on port "
37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "0x%016Lx on adapter %s " "(debug info %d)\n",
37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     unit->fcp_lun, unit->port->wwpn,
37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     zfcp_get_busid_by_unit(unit),
37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     fsf_req->qtcb->bottom.io.fcp_cmnd_length);
37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_cmd_len_nv");
37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3780d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, "
37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n",
37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, unit->fcp_lun);
37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
3791d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			| ZFCP_STATUS_FSFREQ_RETRY;
37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
380265a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann 			zfcp_test_link(unit->port);
38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME(hw) need proper specs for proper action */
38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* let scsi stack deal with retries and escalation */
38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
3812516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann 			    ("Unknown status qualifier 0x%x arrived.\n",
38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(fsf_req->adapter->erp_dbf, 0,
38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(u32));
38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3821516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_RSP_AVAILABLE:
38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof(u32));
38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) {
38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval =
38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    zfcp_fsf_send_fcp_command_task_management_handler(fsf_req);
38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req);
3843059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		fsf_req->unit = NULL;
3844059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		zfcp_unit_put(unit);
38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_handler
38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *scpnt;
38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *)
38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3868059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = fsf_req->unit;
38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
3871059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	scpnt = (struct scsi_cmnd *) fsf_req->data;
38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(!scpnt)) {
38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG
38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("Command with fsf_req %p is not associated to "
38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "a scsi command anymore. Aborted?\n", fsf_req);
38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME: (design) mid-layer should handle DID_ABORT like
38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        DID_SOFT_ERROR by retrying the request for devices
38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        that allow retries.
38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n");
38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_SOFT_ERROR);
38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_driver_byte(&scpnt->result, SUGGEST_RETRY);
38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_ERROR\n");
38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_ERROR);
38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set message byte of result in SCSI command */
38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= COMMAND_COMPLETE << 8;
38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte
39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of result in SCSI command
39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->scsi_status)) {
39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* DEBUG */
39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status for SCSI Command:\n");
39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      scpnt->cmnd, scpnt->cmd_len);
39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("SCSI status code 0x%x\n",
39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_iu->scsi_status);
39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu));
39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu),
39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_sns_len);
39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("rsp_len is valid\n");
39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fcp_rsp_info[3]) {
39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_GOOD:
39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ok, continue */
39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_TRACE("no failure or Task Management "
39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "Function complete\n");
39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_OK);
39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_LENGTH_MISMATCH:
39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"length differs from the burst length. "
39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s",
39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_FIELD_INVALID:
39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* driver or hardware bug */
39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fields were incorrectly set up. "
39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s",
39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_RO_MISMATCH:
39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The FCP response code indicates "
39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that conflicting  values for the "
39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fibrechannel payload offset from the "
39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"header were found. "
39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s.\n",
39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: An invalid FCP response "
39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"code was detected for a command. "
39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s (debug info 0x%x)\n",
39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fcp_rsp_info[3]);
39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
39926f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for sense data */
39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = FSF_FCP_RSP_SIZE -
39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n",
40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sns_len);
40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n",
40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       SCSI_SENSE_BUFFERSIZE);
40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scpnt->result);
40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->cmnd, scpnt->cmd_len);
40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_rsp_iu->fcp_sns_len);
40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(&scpnt->sense_buffer,
40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->sense_buffer, sns_len);
40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for overrun */
40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) {
40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data overrun was detected for a command. "
40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for underrun */
40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data underrun was detected for a command. "
40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scpnt->resid = fcp_rsp_iu->fcp_resid;
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
40466f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			set_host_byte(&scpnt->result, DID_ERROR);
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40528a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
40538a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt);
40548a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
40558a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt);
40568a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
40578a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt);
40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* cleanup pointer (need this especially for abort) */
40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* always call back */
40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags);
40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_management_handler
40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
4090059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&fsf_req->adapter->scsi_er_timer);
40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fcp_rsp_info[3]) {
41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_GOOD:
41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ok, continue */
41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("no failure or Task Management "
41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "Function complete\n");
41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_UNSUPP:
41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is not supported on the target device "
41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s\n ",
41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP;
41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_FAILED:
41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"failed to complete successfully. "
41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s.\n",
41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An invalid FCP response "
41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"code was detected for a command. "
41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s "
41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_info[3]);
41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      skip_fsfstatus:
41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file
41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Initiator of the control file upload/download FSF requests
41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0           - FSF request is successfuly created and queued
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EOPNOTSUPP - The FCP adapter does not have Control File support
41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL     - Invalid direction specified
41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -ENOMEM     - Insufficient memory
41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM      - Cannot create FSF request or place it in QDIO queue
41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file(struct zfcp_adapter *adapter,
41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_fsf_req **fsf_req_ptr,
41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 fsf_command,
41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 option,
41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_sg_list *sg_list)
41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list *timer;
41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req_flags = 0;
41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int direction;
41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(adapter->supported_features & FSF_FEATURE_CFDC)) {
41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n",
41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EOPNOTSUPP;
41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_command) {
41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_WRITE;
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((option != FSF_CFDC_OPTION_FULL_ACCESS) &&
41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS))
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req_flags = ZFCP_WAIT_FOR_SBAL;
41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_UPLOAD_CONTROL_FILE:
41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_READ;
41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command);
41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!timer) {
41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -ENOMEM;
41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	}
41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     NULL, &lock_flags, &fsf_req);
42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FSF request for the "
42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter %s\n",
42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unlock_queue_lock;
42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= direction;
42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->option = option;
42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_list->count > 0) {
42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int bytes;
42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sg_list->sg, sg_list->count,
42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_MAX_SBALS_PER_REQ);
42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) {
42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO(
42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"error: Could not create sufficient number of "
42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"SBALS for an FSF request to the adapter %s\n",
42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -ENOMEM;
42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto free_fsf_req;
42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(timer);
42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->function = zfcp_fsf_request_timeout_handler;
42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->data = (unsigned long) adapter;
42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_send(fsf_req, timer);
42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("initiation of cfdc up/download failed"
42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s)\n",
42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto free_fsf_req;
42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the "
42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"adapter %s\n",
42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"download" : "upload",
42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(fsf_req->completion_wq,
42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_ptr = fsf_req;
42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(timer);
42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto free_timer;
42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_fsf_req:
42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_queue_lock:
42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_timer:
42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(timer);
42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
42731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file_handler
42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Handler of the control file upload/download FSF requests
42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0       - FSF request successfuly processed
42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EAGAIN - Operation has to be repeated because of a temporary problem
42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EACCES - There is no permission to execute an operation
42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM  - The control file is not in a right format
42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO    - There is a problem with the FCP adapter
42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL - Invalid operation
42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EFAULT - User space memory I/O operation fault
42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header = &fsf_req->qtcb->header;
42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support;
42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"The FSF request has been successfully completed "
43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"on the adapter %s\n",
43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_OPERATION_PARTIALLY_SUCCESSFUL:
43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (header->fsf_status_qual.word[0]) {
43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43116f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			case FSF_SQ_CFDC_HARDENED_ON_SE:
43126f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				ZFCP_LOG_NORMAL(
43136f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"CFDC on the adapter %s has being "
43146f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"hardened on primary and secondary SE\n",
43156f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter));
43166f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				break;
43176f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>
43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be saved on the SE\n",
43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2:
43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be copied to the secondary SE\n",
43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC could not be hardened "
43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on the adapter %s\n",
43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EAGAIN;
43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_AUTHORIZATION_FAILURE:
43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s does not accept privileged commands\n",
43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EACCES;
43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CFDC_ERROR_DETECTED:
43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Error at position %d in the CFDC, "
43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"CFDC is discarded by the adapter %s\n",
43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status_qual.word[0],
43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_UPDATE_ERROR:
43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s cannot harden the control file, "
43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"file is discarded\n",
43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_TOO_LARGE:
43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Control file is too large, file is discarded "
43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"by the adapter %s\n",
43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_CONFLICT_DETECTED:
43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been discarded by the adapter %s, "
43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"because activation would impact "
43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONFLICTS_OVERRULED:
43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been activated on the adapter %s, "
43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"but activation has impacted "
43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, "
44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"op_subtype=0x%x)\n",
44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bottom->operation_subtype);
44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
44151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown/unexpected FSF status 0x%08x "
44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"was presented on the adapter %s\n",
44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status,
44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval");
44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_check(unsigned long *flags,
44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct zfcp_qdio_queue *queue, int needed)
44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&queue->queue_lock, *flags);
44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(atomic_read(&queue->free_count) >= needed))
44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&queue->queue_lock, *flags);
44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set qtcb pointer in fsf_req and initialize QTCB
44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
44558a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetyninzfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
44588a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->prefix.req_seq_no = fsf_req->adapter->fsf_req_seq_no;
44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req;
44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
44618a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_req->fsf_command];
44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req;
44648a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter for which request queue is examined
44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags indicating whether to wait for needed SBAL or not
44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @lock_flags: lock_flags if queue_lock is taken
44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locks: lock adapter->request_queue->queue_lock on success
44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      unsigned long *lock_flags)
44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        long ret;
44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = wait_event_interruptible_timeout(adapter->request_wq,
44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1),
44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       ZFCP_SBAL_TIMEOUT);
44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ret)
44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1))
44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EIO;
44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_create
44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	create an FSF request at the specified adapter and
45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		setup common fields
45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	-ENOMEM if there was insufficient memory for a request
45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO if no qdio buffers could be allocate to the request
45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL/-EPERM on bug conditions in req_dequeue
45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              0 in success
45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note:        The created request is returned by reference.
45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:	lock of concerned request queue must not be held,
45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		but is held on completion (write, irqsave)
45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    mempool_t *pool, unsigned long *lock_flags,
45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    struct zfcp_fsf_req **fsf_req_p)
45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allocate new FSF request */
45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(NULL == fsf_req)) {
45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "the outbound (send) queue.\n");
45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_fsf_req;
45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45328a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->adapter = adapter;
45338a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->fsf_command = fsf_cmd;
45348a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
45358a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin        zfcp_fsf_req_qtcb_init(fsf_req);
45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* initialize waitqueue which may be used to wait on
45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this request completion */
45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&fsf_req->completion_wq);
45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if(ret < 0) {
45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_sbals;
45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We hold queue_lock here. Check if QDIOUP is set and let request fail
45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if it is not set (see also *_open_qdio and *_close_qdio).
45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags);
45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EIO;
45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_sbals;
45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45578a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (fsf_req->qtcb) {
45588a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->seq_no = adapter->fsf_req_seq_no;
45598a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
45608a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	}
45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_number = 1;
45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_first = req_queue->free_index;
45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_curr = req_queue->free_index;
45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        fsf_req->sbale_curr = 1;
45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup common SBALE fields */
45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].addr = fsf_req;
45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].addr = (void *) fsf_req->qtcb;
45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].length = sizeof(struct fsf_qtcb);
45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                       fsf_req->sbal_number, fsf_req->sbal_first);
45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_sbals:
45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* dequeue new FSF request previously enqueued */
45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_fsf_req:
45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&req_queue->queue_lock, *lock_flags);
45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_p = fsf_req;
45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_send
45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	start transfer of FSF request via QDIO
46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	0 - request transfer succesfully started
46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		!0 - start of request transfer failed
46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue;
46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
46118a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	int inc_seq_no;
46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int new_distance_from_int;
46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue = &adapter->request_queue,
46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME(debug): remove it later */
46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0);
46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags);
46231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n");
46241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      sbale[1].length);
46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* put allocated FSF request at list tail */
46281db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head);
46301db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46328a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	inc_seq_no = (fsf_req->qtcb != NULL);
46338a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
46341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* figure out expiration time of timeout and start timeout */
46351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(timer)) {
46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timer->expires += jiffies;
46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(timer);
46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("request queue of adapter %s: "
46411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "next free SBAL is %i, %i free SBALs\n",
46421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       req_queue->free_index,
46441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       atomic_read(&req_queue->free_count));
46451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, "
46471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "index_in_queue=%i, count=%i, buffers=%p\n",
46481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
46491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       QDIO_FLAG_SYNC_OUTPUT,
46501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       0, fsf_req->sbal_first, fsf_req->sbal_number,
46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       &req_queue->buffer[fsf_req->sbal_first]);
46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * adjust the number of free SBALs in request queue as well as
46551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * position of first one
46561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_sub(fsf_req->sbal_number, &req_queue->free_count);
46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count));
46591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index += fsf_req->sbal_number;	  /* increase */
46601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q;  /* wrap if needed */
46611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46638a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->issued = get_clock();
46648a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
46651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = do_QDIO(adapter->ccw_device,
46661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 QDIO_FLAG_SYNC_OUTPUT,
46671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval)) {
46701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Queues are down..... */
46711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME(potential race):
46741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * timer might be expired (absolutely unlikely)
46751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
46761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (timer)
46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			del_timer(timer);
46781db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
46791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del(&fsf_req->list);
46801db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * adjust the number of free SBALs in request queue as well as
46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * position of first one
46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_qdio_zero_sbals(req_queue->buffer,
46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     fsf_req->sbal_first, fsf_req->sbal_number);
46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_add(fsf_req->sbal_number, &req_queue->free_count);
46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index -= fsf_req->sbal_number;	 /* increase */
46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG
46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			("error: do_QDIO failed. Buffers could not be enqueued "
46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 "to request queue.\n");
46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->distance_from_int = new_distance_from_int;
46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * increase FSF sequence counter -
46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this must only be done for request successfully enqueued to
46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * QDIO this rejected requests may be cleaned up by calling
47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * routines  resulting in missing sequence counter values
47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * otherwise,
47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
47038a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Don't increase for unsolicited status */
47058a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		if (inc_seq_no)
47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adapter->fsf_req_seq_no++;
47078a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* count FSF requests pending */
47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_inc(&adapter->fsf_reqs_active);
47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ZFCP_LOG_AREA
4715