zfcp_fsf.c revision 869b2b444c58302e3233ce0b671fabf28135a37d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
24a9d2d8bf989c77b54add430932fa5ed8a80dba9Andreas Herrmann * This file is part of the zfcp device driver for
34a9d2d8bf989c77b54add430932fa5ed8a80dba9Andreas Herrmann * FCP adapters for IBM System z9 and zSeries.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
54a9d2d8bf989c77b54add430932fa5ed8a80dba9Andreas Herrmann * (C) Copyright IBM Corp. 2002, 2006
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2, or (at your option)
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zfcp_ext.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *);
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *);
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_fcp_command_task_management_handler(
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *);
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zfcp_fsf_req_sbal_check(
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *, struct zfcp_qdio_queue *, int);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zfcp_use_one_sbal(
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scatterlist *, int, struct scatterlist *, int);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
452abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmannstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
49aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetyninstatic void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *,
50aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	struct fsf_link_down_info *);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* association between FSF command and FSF QTCB type */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 fsf_qtcb_type[] = {
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char zfcp_act_subtable_type[5][8] = {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"unknown", "OS", "WWPN", "DID", "LUN"
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************/
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*************** FSF related Functions  *************************/
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************/
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_alloc
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Obtains an fsf_req and potentially a qtcb (for all but
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              unsolicited requests) via helper functions
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              Does some initial fsf request set-up.
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	pointer to allocated fsf_req if successfull
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL otherwise
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:       none
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct zfcp_fsf_req *
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t size;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *ptr;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req_flags & ZFCP_REQ_NO_QTCB)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = sizeof(struct zfcp_fsf_req);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
103dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		size = sizeof(struct zfcp_fsf_req_qtcb);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	if (likely(pool))
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr = mempool_alloc(pool, GFP_ATOMIC);
107dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	else {
108dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		if (req_flags & ZFCP_REQ_NO_QTCB)
109dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens			ptr = kmalloc(size, GFP_ATOMIC);
110dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		else
111dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens			ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
11254e6ecb23951b195d02433a741c7f7cb0b796c78Christoph Lameter					       GFP_ATOMIC);
113dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	if (unlikely(!ptr))
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ptr, 0, size);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req_flags & ZFCP_REQ_NO_QTCB) {
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = (struct zfcp_fsf_req *) ptr;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
123dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req;
124dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		fsf_req->qtcb =	&((struct zfcp_fsf_req_qtcb *) ptr)->qtcb;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->pool = pool;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_free
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Frees the memory of an fsf_req (and potentially a qtcb) or
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              returns it into the pool via helper functions.
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     sod all
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:       none
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1431db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmannvoid
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
146dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	if (likely(fsf_req->pool)) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_free(fsf_req, fsf_req->pool);
148dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
149dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
150dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens
151dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	if (fsf_req->qtcb) {
152dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req);
153dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
154dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
155dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens
156dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	kfree(fsf_req);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke/*
160869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Never ever call this without shutting down the adapter first.
161869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Otherwise the adapter would continue using and corrupting s390 storage.
162869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Included BUG_ON() call to ensure this is done.
163869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * ERP is supposed to be the only user of this function.
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1656fcc47111ae14f284007e1b9a5002babb01d913cSwen Schilligvoid zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
167869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	struct zfcp_fsf_req *fsf_req, *tmp;
168fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	unsigned long flags;
1696fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig	LIST_HEAD(remove_queue);
170869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	unsigned int i;
171fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
172869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status));
173fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock_irqsave(&adapter->req_list_lock, flags);
174fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	atomic_set(&adapter->reqs_active, 0);
175869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	for (i = 0; i < REQUEST_LIST_SIZE; i++)
1766fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig		list_splice_init(&adapter->req_list[i], &remove_queue);
177fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
178fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
179869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {
180869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke		list_del(&fsf_req->list);
181869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke		fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
182869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke		zfcp_fsf_req_complete(fsf_req);
1836fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig	}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_complete
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	Updates active counts and timers for openfcp-reqs
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              May cleanup request after req_eval returns
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	0 - success
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		!0 - failure
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * context:
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cleanup;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Status read response received\n");
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Note: all cleanup handling is done in the callchain of
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the function call-chain below.
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_status_read_handler(fsf_req);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2112abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	} else {
2122abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		del_timer(&fsf_req->timer);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_protstatus_eval(fsf_req);
2142abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * fsf_req may be deleted due to waking up functions, so
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * cleanup is saved here and used later
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cleanup = 1;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cleanup = 0;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* cleanup request if requested by initiator */
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(cleanup)) {
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * lock must not be held here since it will be
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * grabed by the called routine, too
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2341db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		zfcp_fsf_req_free(fsf_req);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* notify initiator waiting for the requests completion */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: Race! We must not access fsf_req here as it might have been
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * flag. It's an improbable case. But, we have the same paranoia for
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the cleanup flag already.
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Might better be handled using complete()?
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (setting the flag and doing wakeup ought to be atomic
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  with regard to checking the flag as long as waitqueue is
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  part of the to be released structure)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up(&fsf_req->completion_wq);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_protstatus_eval
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates the QTCB of the finished FSF request
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and initiates appropriate actions
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		(usually calling FSF command specific handlers)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * context:
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
2738a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	struct fsf_qtcb *qtcb = fsf_req->qtcb;
2748a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	union fsf_prot_status_qual *prot_status_qual =
2758a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		&qtcb->prefix.prot_status_qual;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2778a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_response(fsf_req);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n",
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (unsigned long) fsf_req);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_protstatus;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* log additional information provided by FSF (if any) */
288862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens	if (likely(qtcb->header.log_length)) {
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do not trust them ;-) */
290862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens		if (unlikely(qtcb->header.log_start >
291862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens			     sizeof(struct fsf_qtcb))) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: ULP (FSF logging) log data starts "
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "beyond end of packet header. Ignored. "
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "(start=%i, size=%li)\n",
2968a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			     qtcb->header.log_start,
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     sizeof(struct fsf_qtcb));
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto forget_log;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
300862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens		if (unlikely((size_t) (qtcb->header.log_start +
301862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens				       qtcb->header.log_length) >
302862794fa3fd4c8a44ee22582418736c93e0d3c3aHeiko Carstens			     sizeof(struct fsf_qtcb))) {
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"beyond end of packet header. Ignored. "
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"(start=%i, length=%i, size=%li)\n",
3068a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin					qtcb->header.log_start,
3078a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin					qtcb->header.log_length,
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct fsf_qtcb));
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto forget_log;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("ULP log data: \n");
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
3138a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			      (char *) qtcb + qtcb->header.log_start,
3148a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			      qtcb->header.log_length);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds forget_log:
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF Protocol Status */
3198a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	switch (qtcb->prefix.prot_status) {
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_GOOD:
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_FSF_STATUS_PRESENTED:
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_QTCB_VERSION_ERROR:
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: The adapter %s contains "
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"microcode of version 0x%x, the device driver "
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports 0x%x. Aborting.\n",
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
3308a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				prot_status_qual->version_error.fsf_version,
3318a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				ZFCP_QTCB_VERSION);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_SEQ_NUMB_ERROR:
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Sequence number mismatch between "
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"driver (0x%x) and adapter %s (0x%x). "
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Restarting all operations on this adapter.\n",
3408a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				qtcb->prefix.req_seq_no,
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
3428a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				prot_status_qual->sequence_error.exp_req_seq_no);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_UNSUPP_QTCB_TYPE:
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: Packet header type used by the "
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"device driver is incompatible with "
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"that used on adapter %s. "
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter.\n",
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&(adapter->status));
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_DUPLICATE_REQUEST_ID:
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx "
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"to the adapter %s is ambiguous. "
367aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"Stopping all operations on this adapter.\n",
368aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				*(unsigned long long*)
369aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				(&qtcb->bottom.support.req_handle),
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_LINK_DOWN:
376aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		zfcp_fsf_link_down_info_eval(adapter,
377aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					     &prot_status_qual->link_down_info);
3782f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		zfcp_erp_adapter_reopen(adapter, 0);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_REEST_QUEUE:
3838a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter with "
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%s was re-plugged. "
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "Re-starting operations on this adapter.\n",
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* All ports should be marked as ready to run again */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_adapter_status(adapter,
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_STATUS_COMMON_RUNNING,
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_SET);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter,
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					| ZFCP_STATUS_COMMON_ERP_FAILED);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PROT_ERROR_STATE:
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: The adapter %s "
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"has entered the error state. "
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Restarting all operations on this "
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter.\n",
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Transfer protocol status information "
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"provided by the adapter %s "
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is not compatible with the device driver. "
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. "
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x).\n",
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
4158a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				qtcb->prefix.prot_status);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_protstatus:
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * always call specific handlers to give them a chance to do
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * something meaningful even in error cases
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_fsfstatus_eval(fsf_req);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_fsfstatus_eval
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FSF status of completed FSF request
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and acts accordingly
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF Status */
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_COMMAND:
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is "
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not known by the adapter %s "
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. "
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x).\n",
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter),
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_command);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_RSP_AVAILABLE:
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("FCP Sense data will be presented to the "
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "SCSI stack.\n");
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_fsfstatus_qual_eval(fsf_req);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * always call specific handlers to give them a chance to do
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * something meaningful even in error cases
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_dispatch(fsf_req);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_fsfstatus_qual_eval
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FSF status-qualifier of completed FSF request
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		and acts accordingly
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_FCP_RSP_AVAILABLE:
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_RETRY_IF_POSSIBLE:
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The SCSI-stack may now issue retries or escalate */
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_COMMAND_ABORTED:
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Carry the aborted state on to upper layer */
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_NO_RECOM:
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"problem on the adapter %s "
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Stopping all operations on this adapter. ",
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter));
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_ULP_PROGRAMMING_ERROR:
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer "
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(adapter %s)\n",
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(fsf_req->adapter));
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_NO_RETRY_POSSIBLE:
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* dealt with in the respective functions */
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Additional status info could "
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not be interpreted properly.\n");
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
536aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin/**
537aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * zfcp_fsf_link_down_info_eval - evaluate link down information block
538aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin */
539aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetyninstatic void
540aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetyninzfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
541aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			     struct fsf_link_down_info *link_down)
542aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin{
543ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
544ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	                     &adapter->status))
545ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin		return;
546ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
547ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
548ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
5492f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	if (link_down == NULL)
5502f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		goto out;
551ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
552aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (link_down->error_code) {
553aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_LIGHT:
554aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
555aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(no light detected)\n",
556aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
557aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
558aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WRAP_PLUG:
559aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
560aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(wrap plug detected)\n",
561aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
562aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
563aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP:
564aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
565aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(adjacent node on link does not support FCP)\n",
566aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
567aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
568aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FIRMWARE_UPDATE:
569aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
570aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(firmware update in progress)\n",
571aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
572aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			break;
573aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_INVALID_WWPN:
574aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
575aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(duplicate or invalid WWPN detected)\n",
576aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
577aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
578aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
579aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
580aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(no support for NPIV by Fabric)\n",
581aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
582aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
583aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP_RESOURCES:
584aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
585aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(out of resource in FCP daughtercard)\n",
586aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
587aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
588aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
589aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
590aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(out of resource in Fabric)\n",
591aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
592aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
593aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
594aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
595aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(unable to Fabric login)\n",
596aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
597aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
598aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
599aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n",
600aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
601aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
602aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
603aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n",
604aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
605aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
606aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
607aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n",
608aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
609aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
610aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	default:
611aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("The local link to adapter %s is down "
612aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				"(warning: unknown reason code %d)\n",
613aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter),
614aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->error_code);
615aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
616aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
617aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
618aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_DEBUG("Debug information to link down: "
619aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "primary_status=0x%02x "
620aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "ioerr_code=0x%02x "
621aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "action_code=0x%02x "
622aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "reason_code=0x%02x "
623aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "explanation_code=0x%02x "
624aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		               "vendor_specific_code=0x%02x\n",
625aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->primary_status,
626aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->ioerr_code,
627aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->action_code,
628aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->reason_code,
629aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->explanation_code,
630aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				link_down->vendor_specific_code);
631aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
6322f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann out:
6332f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	zfcp_erp_adapter_failed(adapter);
634aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin}
635aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:	zfcp_fsf_req_dispatch
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	calls the appropriate command specific handler
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_erp_action *erp_action = fsf_req->erp_action;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->fsf_command) {
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_FCP_CMND:
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_fcp_command_handler(fsf_req);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_ABORT_FCP_CMND:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_abort_fcp_command_handler(fsf_req);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_SEND_GENERIC:
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_ct_handler(fsf_req);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_OPEN_PORT_WITH_DID:
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_open_port_handler(fsf_req);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_OPEN_LUN:
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_open_unit_handler(fsf_req);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_LUN:
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_unit_handler(fsf_req);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_PORT:
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_port_handler(fsf_req);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_CLOSE_PHYSICAL_PORT:
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_close_physical_port_handler(fsf_req);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_EXCHANGE_CONFIG_DATA:
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_exchange_config_data_handler(fsf_req);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_EXCHANGE_PORT_DATA:
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_exchange_port_data_handler(fsf_req);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_SEND_ELS:
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_send_els_handler(fsf_req);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_control_file_handler(fsf_req);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_UPLOAD_CONTROL_FILE:
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_control_file_handler(fsf_req);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is "
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"not supported by the adapter %s\n",
7098a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command)
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Command issued by the device driver differs "
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "from the command returned by the adapter %s "
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "(debug info 0x%x, 0x%x).\n",
7158a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			     zfcp_get_busid_by_adapter(adapter),
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->fsf_command,
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->qtcb->header.fsf_command);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!erp_action)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_erp_async_handler(erp_action, 0);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_status_read
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	initiates a Status Read command at the specified adapter
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     req_flags | ZFCP_REQ_NO_QTCB,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_status_read,
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create unsolicited status "
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "buffer for adapter %s.\n",
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_create;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        fsf_req->sbale_curr = 2;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status_buffer =
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!status_buffer) {
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: could not get some buffer\n");
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_buf;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer));
768059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) status_buffer;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* insert pointer to respective buffer */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_curr(fsf_req);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale->addr = (void *) status_buffer;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale->length = sizeof(struct fsf_status_read_buffer);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7752abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status "
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "environment.\n");
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_send;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n",
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter));
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_send:
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mempool_free(status_buffer, adapter->pool.data_status_read);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_buf:
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_create:
7928a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
806059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock_irqsave(&zfcp_data.config_lock, flags);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(port, &adapter->port_list_head, list)
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK))
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
8171d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"nonexisting port with d_id 0x%06x on "
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s. Ignored.\n",
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->d_id & ZFCP_DID_MASK,
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (status_buffer->status_subtype) {
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 3, "unsol_pc_phys:");
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(port, 0);
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SUB_ERROR_PORT:
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "unsol_pc_err:");
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_shutdown(port, 0);
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "unsol_unk_sub:");
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&status_buffer->status_subtype, sizeof (u32));
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"for a reopen indication on port with "
8421d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"d_id 0x%06x on the adapter %s. "
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Ignored. (debug info 0x%x)\n",
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->d_id,
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->status_subtype);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_status_read_handler
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open Port command
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_status_read_buffer *status_buffer =
865059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		(struct fsf_status_read_buffer *) fsf_req->data;
866b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner	struct fsf_bit_error_payload *fsf_bit_error;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
8698a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_free(status_buffer, adapter->pool.data_status_read);
8711db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann		zfcp_fsf_req_free(fsf_req);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8758a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer);
8768a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (status_buffer->status_type) {
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_PORT_CLOSED:
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_status_read_port_closed(fsf_req);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_INCOMING_ELS:
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_incoming_els(fsf_req);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n",
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
893b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		fsf_bit_error = (struct fsf_bit_error_payload *)
894b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner			status_buffer->payload;
895b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		ZFCP_LOG_NORMAL("Warning: bit error threshold data "
896b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "received (adapter %s, "
897b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "link failures = %i, loss of sync errors = %i, "
898b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "loss of signal errors = %i, "
899b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "primitive sequence errors = %i, "
900b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "invalid transmission word errors = %i, "
901b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "CRC errors = %i)\n",
902b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    zfcp_get_busid_by_adapter(adapter),
903b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->link_failure_error_count,
904b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->loss_of_sync_error_count,
905b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->loss_of_signal_error_count,
906b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->primitive_sequence_error_count,
907b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->invalid_transmission_word_error_count,
908b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->crc_error_count);
909b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		ZFCP_LOG_INFO("Additional bit error threshold data "
910b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "(adapter %s, "
911b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "primitive sequence event time-outs = %i, "
912b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "elastic buffer overrun errors = %i, "
913b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "advertised receive buffer-to-buffer credit = %i, "
914b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "current receice buffer-to-buffer credit = %i, "
915b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "advertised transmit buffer-to-buffer credit = %i, "
916b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    "current transmit buffer-to-buffer credit = %i)\n",
917b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    zfcp_get_busid_by_adapter(adapter),
918b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->primitive_sequence_event_timeout_count,
919b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->elastic_buffer_overrun_error_count,
920b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->advertised_receive_b2b_credit,
921b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->current_receive_b2b_credit,
922b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->advertised_transmit_b2b_credit,
923b7a52fa7fff2309031a2f849bc489206afd2fa4aRalph Wuerthner		    fsf_bit_error->current_transmit_b2b_credit);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_LINK_DOWN:
927aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		switch (status_buffer->status_subtype) {
928aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
929aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_INFO("Physical link to adapter %s is down\n",
930aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      zfcp_get_busid_by_adapter(adapter));
931ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin			zfcp_fsf_link_down_info_eval(adapter,
932ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				(struct fsf_link_down_info *)
933ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				&status_buffer->payload);
934aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			break;
935aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		case FSF_STATUS_READ_SUB_FDISC_FAILED:
936aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_INFO("Local link to adapter %s is down "
937aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      "due to failed FDISC login\n",
938ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				      zfcp_get_busid_by_adapter(adapter));
939ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin			zfcp_fsf_link_down_info_eval(adapter,
940ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				(struct fsf_link_down_info *)
941ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				&status_buffer->payload);
942aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			break;
943aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
944aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_INFO("Local link to adapter %s is down "
945aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      "due to firmware update on adapter\n",
946aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      zfcp_get_busid_by_adapter(adapter));
947ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin			zfcp_fsf_link_down_info_eval(adapter, NULL);
948aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			break;
949aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		default:
950aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_INFO("Local link to adapter %s is down "
951aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      "due to unknown reason\n",
952aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin				      zfcp_get_busid_by_adapter(adapter));
953ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin			zfcp_fsf_link_down_info_eval(adapter, NULL);
954aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		};
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_LINK_UP:
958aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. "
959ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				"Restarting operations on this adapter\n",
960ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin				zfcp_get_busid_by_adapter(adapter));
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* All ports should be marked as ready to run again */
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_adapter_status(adapter,
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_STATUS_COMMON_RUNNING,
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       ZFCP_SET);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter,
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					| ZFCP_STATUS_COMMON_ERP_FAILED);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9709eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin	case FSF_STATUS_READ_NOTIFICATION_LOST:
9719eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin		ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: "
9729eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				"adapter %s%s%s%s%s%s%s%s%s\n",
9739eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				zfcp_get_busid_by_adapter(adapter),
9749eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9759eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_INCOMING_ELS) ?
9769eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", incoming ELS" : "",
9779eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9789eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_SENSE_DATA) ?
9799eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", sense data" : "",
9809eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9819eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_LINK_STATUS) ?
9829eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", link status change" : "",
9839eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9849eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_PORT_CLOSED) ?
9859eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", port close" : "",
9869eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9879eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ?
9889eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", bit error exception" : "",
9899eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9909eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_ACT_UPDATED) ?
9919eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", ACT update" : "",
9929eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9939eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_ACT_HARDENED) ?
9949eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", ACT hardening" : "",
9959eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin				(status_buffer->status_subtype &
9969eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ?
9979eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin					", adapter feature change" : "");
9989eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin
9999eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin		if (status_buffer->status_subtype &
10009eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin		    FSF_STATUS_READ_SUB_ACT_UPDATED)
10019eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			zfcp_erp_adapter_access_changed(adapter);
10029eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin		break;
10039eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_CFDC_UPDATED:
10058a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n",
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_access_changed(adapter);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_STATUS_READ_CFDC_HARDENED:
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status_buffer->status_subtype) {
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE:
10138a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n",
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2:
10178a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied "
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "to the secondary SE\n",
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
10228a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin			ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n",
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1027aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
1028aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		debug_text_event(adapter->erp_dbf, 2, "unsol_features:");
1029aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		ZFCP_LOG_INFO("List of supported features on adapter %s has "
1030aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			      "been changed from 0x%08X to 0x%08X\n",
1031aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			      zfcp_get_busid_by_adapter(adapter),
1032aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			      *(u32*) (status_buffer->payload + 4),
1033aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			      *(u32*) (status_buffer->payload));
1034aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		adapter->adapter_features = *(u32*) status_buffer->payload;
1035aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
1036aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
10388a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown "
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"type was received (debug info 0x%x)\n",
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				status_buffer->status_type);
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n",
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       status_buffer);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) status_buffer,
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (struct fsf_status_read_buffer));
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mempool_free(status_buffer, adapter->pool.data_status_read);
10491db2c9c0931a53fe013db55fd2ff58859db31e8dAndreas Herrmann	zfcp_fsf_req_free(fsf_req);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * recycle buffer and start new request repeat until outbound
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * queue is empty or adapter shutdown is requested
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FIXME(qdio):
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we may wait in the req_create for 5s during shutdown, so
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * qdio_cleanup will have to wait at least that long before returning
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with failure to allow us a proper cleanup under all circumstances
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FIXME:
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * allocation failure possible? (Is this code needed?)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_status_read(adapter, 0);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Failed to create unsolicited status read "
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request for the adapter %s.\n",
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* temporary fix to avoid status read buffer shortage */
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->status_read_failed++;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed)
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    < ZFCP_STATUS_READ_FAILED_THRESHOLD) {
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("restart adapter %s due to status read "
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "buffer shortage\n",
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(adapter, 0);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_abort_fcp_command
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	tells FSF to abort a running SCSI command
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL - request could not be initiated
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design): should be watched by a timeout !!!
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME(design) shouldn't this be modified to return an int
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *               also...don't know how though
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct zfcp_fsf_req *
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_abort_fcp_command(unsigned long old_req_id,
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct zfcp_adapter *adapter,
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct zfcp_unit *unit, int req_flags)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
11022abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	unsigned long lock_flags;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     req_flags, adapter->pool.fsf_req_abort,
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Failed to create an abort command "
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request for lun 0x%016Lx on port 0x%016Lx "
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s.\n",
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1123059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handle of request which should be aborted */
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11322abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
11332abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Failed to send abort command request "
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, unit->fcp_lun);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
11451d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt		       "(adapter%s, port d_id=0x%06x, "
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "unit x%016Lx, old_req_id=0x%lx)\n",
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->d_id,
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun, old_req_id);
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_abort_fcp_command_handler
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Abort FCP Command request
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
1166059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit;
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char status_qual =
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    new_fsf_req->qtcb->header.fsf_status_qual.word[0];
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1175059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) new_fsf_req->data;
1176059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (new_fsf_req->qtcb->header.fsf_status) {
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status_qual >> 4 != status_qual % 0xf) {
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv0");
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a port
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different). This is
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * fine.
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("Temporary port identifier 0x%x for "
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "port 0x%016Lx on adapter %s invalid. "
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "This may happen occasionally.\n",
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->handle,
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->wwpn,
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_unit(unit));
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("status qualifier:\n");
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv1");
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(unit->port->adapter, 0);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status_qual >> 4 != status_qual % 0xf) {
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 2 */
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv0");
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a unit
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different).
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * This is fine.
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("Warning: Temporary LUN identifier 0x%x of LUN "
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "0x%016Lx on port 0x%016Lx on adapter %s is "
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "invalid. This may happen in rare cases. "
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "Trying to re-establish link.\n",
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->handle,
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->fcp_lun,
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->port->wwpn,
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     zfcp_get_busid_by_unit(unit));
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG("Status qualifier data:\n");
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv1");
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_reopen(unit->port, 0);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_no_exist");
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to "
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "be reopened\n", unit->port->wwpn,
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 2,
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_pboxed");
1255d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO(
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "unit 0x%016Lx on port 0x%016Lx on adapter %s needs "
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "to be reopened\n",
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        unit->fcp_lun, unit->port->wwpn,
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        zfcp_get_busid_by_unit(unit));
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
1267d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        | ZFCP_STATUS_FSFREQ_RETRY;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) {
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
127765a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* SCSI stack will escalate */
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     new_fsf_req->qtcb->header.fsf_status_qual.word[0]);
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(new_fsf_req->adapter->erp_dbf, 0,
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&new_fsf_req->qtcb->header.
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_status_qual.word[0], sizeof (u32));
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_fsf_req->qtcb->header.fsf_status);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_inval:");
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(new_fsf_req->adapter->erp_dbf, 0,
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&new_fsf_req->qtcb->header.fsf_status,
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	one SBALE
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Two scatter-gather lists are passed, one for the reqeust and one for the
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * response.
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_use_one_sbal(struct scatterlist *req, int req_count,
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  struct scatterlist *resp, int resp_count)
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ((req_count == 1) &&
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(resp_count == 1) &&
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&req[0]) &
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 ((unsigned long) (zfcp_sg_to_address(&req[0]) +
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   req[0].length - 1) & PAGE_MASK)) &&
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&resp[0]) &
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                 ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   resp[0].length - 1) & PAGE_MASK)));
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the request
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool: pointer to memory pool, if non-null this pool is used to allocate
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	a struct zfcp_fsf_req
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @erp_action: pointer to erp_action, if non-null the Generic Service request
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	is sent within error recovery
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct zfcp_erp_action *erp_action)
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_fsf_req *fsf_req;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        unsigned long lock_flags;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = ct->port;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = port->adapter;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  pool, &lock_flags, &fsf_req);
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for "
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter: %s\n",
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (zfcp_use_one_sbal(ct->req, ct->req_count,
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              ct->resp, ct->resp_count)){
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* both request buffer and response buffer
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   fit into one sbale each */
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].length = ct->req[0].length;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].length = ct->resp[0].length;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
1386aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	} else if (adapter->adapter_features &
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* try to use chained SBALs */
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->req, ct->req_count,
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->resp, ct->resp_count,
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else {
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* reject send generic request */
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"error: microcode does not support chained SBALs,"
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "CT request too big (adapter %s)\n",
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = -EOPNOTSUPP;
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_send;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* settings in QTCB */
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = port->handle;
143406506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.support.service_class =
143506506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_FC_SERVICE_CLASS_DEFAULT;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.timeout = ct->timeout;
1437059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann        fsf_req->data = (unsigned long) ct;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14398a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_san_dbf_event_ct_request(fsf_req);
14408a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
14412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	if (erp_action) {
14422abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		erp_action->fsf_req = fsf_req;
14432abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		fsf_req->erp_action = erp_action;
14442abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_erp_start_timer(fsf_req);
14452abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	} else
14462abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
14472abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
14482abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	ret = zfcp_fsf_req_send(fsf_req);
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: initiation of CT request failed "
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(adapter %s, port 0x%016Lx)\n",
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter), port->wwpn);
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n",
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter), port->wwpn);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (erp_action != NULL) {
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                erp_action->fsf_req = NULL;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        write_unlock_irqrestore(&adapter->request_queue.queue_lock,
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct_handler - handler for Generic Service requests
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1476059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the Generic Service request is passed using
1477059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_ct.
1478059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the CT request is called which is
1479059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_ct *send_ct;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
1493059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_ct = (struct zfcp_send_ct *) fsf_req->data;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = send_ct->port;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
15058a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_ct_response(fsf_req);
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                retval = 0;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
151006506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
151106506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
151206506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_port(port),
151306506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* reopening link to port */
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_test_link(port);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                default:
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x "
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "arrived.\n",
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send generic service "
15431d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"command (adapter %s, port d_id=0x%06x)\n",
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_port(port), port->d_id);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GENERIC_COMMAND_REJECTED:
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("generic service command rejected "
15651d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id=0x%06x)\n",
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej");
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_HANDLE_NOT_VALID:
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port "
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "0x%016Lx on adapter %s invalid. This may "
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "happen occasionally.\n", port->handle,
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn, zfcp_get_busid_by_port(port));
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv");
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("port needs to be reopened "
15911d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id=0x%06x)\n",
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
1594d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* following states should never occure, all cases avoided
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   in zfcp_fsf_send_ct - but who knows ... */
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("payload size mismatch (adapter: %s, "
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d, resp_buf_length=%d)\n",
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("request size too large (adapter: %s, "
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d)\n",
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length);
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("response size too large (adapter: %s, "
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->resp_buf_length);
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       default:
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n", header->fsf_status);
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:");
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ct->status = retval;
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (send_ct->handler != NULL)
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @els: pointer to struct zfcp_send_els which contains all needed data for
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the command.
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_els(struct zfcp_send_els *els)
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
165813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	u32 d_id;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = els->d_id;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = els->adapter;
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_REQ_AUTO_CLEANUP,
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  NULL, &lock_flags, &fsf_req);
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: creation of ELS request failed "
16721d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id: 0x%06x)\n",
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              zfcp_get_busid_by_adapter(adapter), d_id);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_req;
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (zfcp_use_one_sbal(els->req, els->req_count,
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              els->resp, els->resp_count)){
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* both request buffer and response buffer
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   fit into one sbale each */
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].addr = zfcp_sg_to_address(&els->req[0]);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].length = els->req[0].length;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].length = els->resp[0].length;
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
1688aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	} else if (adapter->adapter_features &
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* try to use chained SBALs */
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                els->req, els->req_count,
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of ELS request failed "
16971d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				      "(adapter %s, port d_id: 0x%06x)\n",
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter), d_id);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0) {
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        } else {
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        }
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                els->resp, els->resp_count,
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_ELS_REQ);
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of ELS request failed "
17141d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				      "(adapter %s, port d_id: 0x%06x)\n",
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter), d_id);
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0) {
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        } else {
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        }
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else {
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* reject request */
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              ", ELS request too big (adapter %s, "
17281d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "port d_id: 0x%06x)\n",
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter), d_id);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = -EOPNOTSUPP;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_send;
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* settings in QTCB */
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.d_id = d_id;
173606506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.support.service_class =
173706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_FC_SERVICE_CLASS_DEFAULT;
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
1739059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) els;
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17438a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_san_dbf_event_els_request(fsf_req);
17448a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
17452abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
17462abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	ret = zfcp_fsf_req_send(fsf_req);
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
17491d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			       "(adapter %s, port d_id: 0x%06x)\n",
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter), d_id);
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
17551d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ret;
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els_handler - handler for ELS commands
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1773059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the ELS command is passed using
1774059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_els.
1775059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the ELS command is called which is
1776059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
178213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	u32 d_id;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_els *send_els;
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1789059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_els = (struct zfcp_send_els *) fsf_req->data;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = send_els->adapter;
179164b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann	port = send_els->port;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = send_els->d_id;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18028a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_els_response(fsf_req);
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
180706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
180806506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
180906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_adapter(adapter),
181006506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
182164b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
182264b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval =
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      (struct zfcp_ls_rjt_par *)
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      &header->fsf_status_qual.word[2]);
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry");
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n",
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(char*)header->fsf_status_qual.word, 16);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("ELS has been rejected because command filter "
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "prohibited sending "
18481d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter: %s, port d_id: 0x%06x)\n",
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter), d_id);
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"ELS request size and ELS response size must be either "
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"both 0, or both greater than 0 "
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n",
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length,
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS request buffer, "
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS request data "
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d)\n",
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length);
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS response buffer, "
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS response data "
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, resp_buf_length=%d)\n",
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, avoided in zfcp_fsf_send_els */
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
18961d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"(adapter %s, port d_id=0x%06x)\n",
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter), d_id);
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (port != NULL)
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_access_denied(port);
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown FSF Status was presented "
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, fsf_status=0x%08x)\n",
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status);
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval");
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_els->status = retval;
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (send_els->handler != 0)
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
19432abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_EXCHANGE_CONFIG_DATA,
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_REQ_AUTO_CLEANUP,
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
19522abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create exchange configuration "
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "data request for adapter %s.\n",
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19602abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19642abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.config.feature_selection =
1965aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_CFDC |
1966aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_LUN_SHARING |
19679eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			FSF_FEATURE_NOTIFICATION_LOST |
1968aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_UPDATE_ALERT;
19692abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
19702abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
19732abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("error: Could not send exchange configuration data "
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "command on the adapter %s\n",
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     zfcp_get_busid_by_adapter(erp_action->adapter));
19792abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("exchange configuration data request initiated "
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s)\n",
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter));
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_config_evaluate
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: fsf_req which belongs to xchg config data request
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1)
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns: -EIO on error, 0 otherwise
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
200613e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	struct Scsi_Host *shost = adapter->scsi_host;
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.config;
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n",
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       bottom->low_qtcb_version, bottom->high_qtcb_version);
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter->fsf_lic_version = bottom->lic_version;
2012aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	adapter->adapter_features = bottom->adapter_features;
2013aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	adapter->connection_features = bottom->connection_features;
20146f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwpn = 0;
20156f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwnn = 0;
20166f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_d_id = 0;
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xchg_ok) {
201913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
202013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
202113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
202213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_speed(shost) = bottom->fc_link_speed;
202313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = bottom->adapter_type;
2025ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		if (fc_host_permanent_port_name(shost) == -1)
2026ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_permanent_port_name(shost) =
2027ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann				fc_host_port_name(shost);
2028ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		if (bottom->fc_topology == FSF_TOPO_P2P) {
2029ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
2030ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_wwpn = bottom->plogi_payload.wwpn;
2031ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_wwnn = bottom->plogi_payload.wwnn;
2032ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_PTP;
2033ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		} else if (bottom->fc_topology == FSF_TOPO_FABRIC)
2034ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
2035ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		else if (bottom->fc_topology == FSF_TOPO_AL)
2036ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
2037ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		else
2038ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
204013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_node_name(shost) = 0;
204113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_name(shost) = 0;
204213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_id(shost) = 0;
204313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
2044ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = 0;
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2048aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hardware_version = bottom->hardware_version;
205013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		memcpy(fc_host_serial_number(shost), bottom->serial_number,
205113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		       min(FC_SERIAL_NUMBER_SIZE, 17));
205213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		EBCASC(fc_host_serial_number(shost),
205313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		       min(FC_SERIAL_NUMBER_SIZE, 17));
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20566f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
205713e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"WWNN 0x%016Lx, "
205813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"WWPN 0x%016Lx, "
20591d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			"S_ID 0x%06x,\n"
206013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"adapter version 0x%x, "
206113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"LIC version 0x%x, "
206213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"FC link speed %d Gb/s\n",
206313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			zfcp_get_busid_by_adapter(adapter),
206413e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			(wwn_t) fc_host_node_name(shost),
206513e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			(wwn_t) fc_host_port_name(shost),
206613e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			fc_host_port_id(shost),
206713e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			adapter->hydra_version,
206813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			adapter->fsf_lic_version,
206913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			fc_host_speed(shost));
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports newer control block "
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions in comparison to this device "
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"driver (try updated device driver)\n",
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "low_qtcb_ver");
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports older control block "
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions than this device driver uses"
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(consider a microcode upgrade)\n",
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "high_qtcb_ver");
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_exchange_config_data_handler
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Exchange Configuration Data command
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
2105aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	struct fsf_qtcb *qtcb = fsf_req->qtcb;
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2110aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (qtcb->header.fsf_status) {
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2116ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		switch (fc_host_port_type(adapter->scsi_host)) {
2117ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_PTP:
21186f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
21196f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"configuration detected at adapter %s\n"
21206f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"Peer WWNN 0x%016llx, "
21216f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer WWPN 0x%016llx, "
21226f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer d_id 0x%06x\n",
21236f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter),
21246f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwnn,
21256f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwpn,
21266f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_d_id);
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "top-p-to-p");
21296f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			break;
2130ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_NLPORT:
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"topology detected at adapter %s "
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"unsupported, shutting down adapter\n",
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "top-al");
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
2139ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_NPORT:
2140aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "network detected at adapter %s.\n",
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"reported by the exchange "
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"configuration command for "
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"the adapter %s is not "
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"of a type known to the zfcp "
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"driver, shutting down adapter\n",
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "unknown-topo");
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2157aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		bottom = &qtcb->bottom.config;
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"allowed by the adapter %s "
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is lower than the minimum "
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"required by the driver (%ld bytes).\n",
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bottom->max_qtcb_size,
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter),
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct fsf_qtcb));
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "qtcb-size");
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_event(fsf_req->adapter->erp_dbf, 0,
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    &bottom->max_qtcb_size, sizeof (u32));
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&adapter->status);
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "xchg-inco");
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2182aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
2183aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
2184aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		zfcp_fsf_link_down_info_eval(adapter,
2185aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			&qtcb->header.fsf_status_qual.link_down_info);
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_event(fsf_req->adapter->erp_dbf, 0,
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &fsf_req->qtcb->header.fsf_status, sizeof (u32));
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
2199aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * @erp_action: ERP action for the adapter for which port data is requested
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: for which port data is requested
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: response to exchange port data request
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2204aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetyninzfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
2205aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			    struct zfcp_adapter *adapter,
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct fsf_qtcb_bottom_port *data)
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_fsf_req *fsf_req;
22102abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	unsigned long lock_flags;
22112abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	int retval = 0;
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2213aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: exchange port data "
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "command not supported by adapter %s\n",
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EOPNOTSUPP;
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
22222448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann				     erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
2223d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens				     NULL, &lock_flags, &fsf_req);
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "exchange port data request for"
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "the adapter %s.\n",
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
22312448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		return retval;
2232aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
2233aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
2234aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (data)
22352448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		fsf_req->data = (unsigned long) data;
2236059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22412448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann	if (erp_action) {
22422448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		erp_action->fsf_req = fsf_req;
22432448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		fsf_req->erp_action = erp_action;
22442abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_erp_start_timer(fsf_req);
22452abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	} else
22462abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22482abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an exchange port data "
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              "command on the adapter %s\n",
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
2254aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (erp_action)
2255aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			erp_action->fsf_req = NULL;
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
22582448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		return retval;
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22612448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22632448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann	if (!erp_action) {
22642448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		wait_event(fsf_req->completion_wq,
22652448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann			   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
22662448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
22672448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann	}
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22712f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann/**
22722f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * zfcp_fsf_exchange_port_evaluate
22732f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * @fsf_req: fsf_req which belongs to xchg port data request
22742f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1)
22752f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann */
22762f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmannstatic void
22772f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmannzfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
22782f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann{
22792f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct zfcp_adapter *adapter;
22802f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct fsf_qtcb *qtcb;
22812f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct fsf_qtcb_bottom_port *bottom, *data;
22822f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct Scsi_Host *shost;
22832f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
22842f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	adapter = fsf_req->adapter;
22852f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	qtcb = fsf_req->qtcb;
22862f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	bottom = &qtcb->bottom.port;
22872f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	shost = adapter->scsi_host;
22882f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
22892f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
22902f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	if (data)
22912f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
22922f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
22932f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
22942f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		fc_host_permanent_port_name(shost) = bottom->wwpn;
22952f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	else
22962f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
22972f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
22982f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	fc_host_supported_speeds(shost) = bottom->supported_speed;
22992f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann}
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23082f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct zfcp_adapter *adapter;
23092f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct fsf_qtcb *qtcb;
23102f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
23112f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	adapter = fsf_req->adapter;
23122f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	qtcb = fsf_req->qtcb;
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2317aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (qtcb->header.fsf_status) {
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
23192f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		zfcp_fsf_exchange_port_evaluate(fsf_req, 1);
2320aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
2321aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
2322aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
23232f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		zfcp_fsf_exchange_port_evaluate(fsf_req, 0);
2324aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
2325aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		zfcp_fsf_link_down_info_eval(adapter,
2326aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			&qtcb->header.fsf_status_qual.link_down_info);
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        default:
2329aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		debug_text_event(adapter->erp_dbf, 0, "xchg-port-ng");
2330aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		debug_event(adapter->erp_dbf, 0,
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &fsf_req->qtcb->header.fsf_status, sizeof(u32));
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL - request could not be initiated
23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
23482abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_PORT_WITH_DID,
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
23572abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open port request "
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23662abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23702abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
23722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
23732abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
23742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23762abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
23772abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send open port request for "
23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
23832abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("open port request initiated "
23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s,  port 0x%016Lx)\n",
23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port_handler
24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open Port command
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2414059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s "
24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is already open.\n",
24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_popen");
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This is a bug, however operation should continue normally
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * if it is simply ignored
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx "
24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"on adapter %s\n",
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The FSF adapter is out of resources. "
24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The remote port 0x%016Lx on adapter %s "
24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "could not be opened. Disabling it.\n",
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_ports");
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_failed(port);
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("The remote port 0x%016Lx on "
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s could not be opened. "
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"Disabling it.\n",
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwpn,
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_port(port));
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "fsf_sq_no_retry");
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_failed(port);
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0],
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save port handle assigned by FSF */
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s "
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "was opened, it's port handle is 0x%x\n",
25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port),
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle);
25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark port as open */
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
2519d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
2520d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
2521d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (fsf_req->qtcb->bottom.support.els1_length <
254275bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner			    sizeof (struct fsf_plogi)) {
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO(
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"warning: insufficient length of "
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"PLOGI payload (%i)\n",
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req->qtcb->bottom.support.els1_length);
25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debug_text_event(fsf_req->adapter->erp_dbf, 0,
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 "fsf_s_short_plogi:");
25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* skip sanity check and assume wwpn is ok */
25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (plogi->serv_param.wwpn != port->wwpn) {
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_LOG_INFO("warning: d_id of port "
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "0x%016Lx changed during "
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "open\n", port->wwpn);
25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debug_text_event(
25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						fsf_req->adapter->erp_dbf, 0,
25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fsf_s_did_change:");
25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					atomic_clear_mask(
25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_STATUS_PORT_DID_DID,
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&port->status);
256175bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner				} else {
25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwnn = plogi->serv_param.wwnn;
256375bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner					zfcp_plogi_evaluate(port, plogi);
256475bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner				}
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, subtype not set in zfcp_fsf_open_port */
25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, "
25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "op_subtype=0x%x)\n",
25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.support.operation_subtype);
25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close port"
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
26052abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PORT,
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
26142abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create a close port request "
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26232abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, 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	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
26282abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
26292abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
26302abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
26312abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
26322abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
26332abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
26342abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
26352abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close port request for "
26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
26412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close port request initiated "
26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port_handler
26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Port FSF command
26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2669059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may happen "
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "occasionally.\n", port->handle,
26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Note: FSF has actually closed the port in this case.
26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The status code is just daft. Fingers crossed for a change
26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, "
27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "port handle 0x%x\n", port->wwpn,
27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_port_status(port,
27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port
27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close physical port"
27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
27392abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
27402abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	unsigned long lock_flags;
27412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	int retval = 0;
27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PHYSICAL_PORT,
27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
27482abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close physical port "
27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27582abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* mark port as being closed */
27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&erp_action->port->status);
27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* save a pointer to this port */
27662abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
27672abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
27682abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
27692abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
27702abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
27712abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
27722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send close physical port "
27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
27782abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close physical port request initiated "
27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port_handler
27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Physical Port FSF command
27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req)
28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2809059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid"
28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port 0x%016Lx). "
28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally.\n",
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle,
28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn);
28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot close "
28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"physical port 0x%016Lx on adapter %s\n",
28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       			ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter "
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s needs to be reopened but it was attempted "
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "to close it physically.\n",
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port));
28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_pboxed");
2866d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This will now be escalated by ERP */
28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s "
29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "physically closed, port handle 0x%x\n",
29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions:	This routine does not check whether the associated
29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		remote port has already been opened. This should be
29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		done by calling routines. Otherwise some status
29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		may be presented by FSF
29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
29432abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_LUN,
29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
29522abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open unit request for "
29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->port->wwpn,
29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29622abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29662abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
29672abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.support.fcp_lun =	erp_action->unit->fcp_lun;
2968aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
29692abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		fsf_req->qtcb->bottom.support.option =
297006506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			FSF_OPEN_LUN_SUPPRESS_BOXING;
29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
29722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->unit;
29732abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
29742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29762abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
29772abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(erp_action->fsf_req);
29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an open unit request "
29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on the adapter %s, port 0x%016Lx for "
29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx\n",
29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun);
29852abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, "
29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit_handler
30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open LUN command
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_queue_designator *queue_designator;
30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
3017aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3019059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	queue_designator = &header->fsf_status_qual.fsf_queue_designator;
30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
3032b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x "
30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s invalid "
30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally\n",
30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_ph_nv");
30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on "
30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s twice.\n",
30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, zfcp_get_busid_by_unit(unit));
30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0,
30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_uopen");
30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on "
30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s\n",
30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun, unit->port->wwpn,
30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
3095d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (header->fsf_status_qual.word[0] != 0) {
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port "
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"with WWPN 0x%Lx "
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"connected to the adapter %s "
31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is already in use in LPAR%d, CSS%d\n",
31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->hla,
31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->cssid);
31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[4];
31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[5];
31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the "
31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"remote port with WWPN 0x%Lx "
31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"connected to the adapter %s "
31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"is denied (%s rule %d)\n",
31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun,
31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_act_subtable_type[subtable],
31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rule);
31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2,
31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_l_sh_vio");
31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The adapter ran out of resources. "
31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "There is no handle (temporary port identifier) "
31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "available for unit 0x%016Lx on port 0x%016Lx "
31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s\n",
31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1,
31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_units");
31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_failed(unit);
31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Re-establish link to port */
31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
316365a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 0,
31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(adapter->erp_dbf, 0,
31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save LUN handle assigned by FSF */
31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on "
31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s opened, port handle 0x%x\n",
31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as open */
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
3205aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
3206aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
3207aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
3208aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
3209aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
3210aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
3211aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
3212aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
3213aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("read-only access for unit "
32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"(adapter %s, wwpn=0x%016Lx, "
32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fcp_lun=0x%016Lx)\n",
32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun);
32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("exclusive access of read-only "
32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_failed(unit);
32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("shared access of read-write "
32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		zfcp_erp_unit_failed(unit);
32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_s_inval:");
32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit
32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of fsf_req - request successfully initiated
32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NULL -
32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions: This routine does not check whether the associated
32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              remote port/lun has already been opened. This should be
32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              done by calling routines. Otherwise some status
32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              may be presented by FSF
32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
32792abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_LUN,
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
32882abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close unit request for "
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32982abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33022abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
33032abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
33052abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->unit;
33062abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
33072abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33092abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
33102abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(erp_action->fsf_req);
33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close unit request for "
33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n",
33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
33172abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, "
33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit_handler
33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close LUN FSF command
33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3345059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may "
33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "happen in rare circumstances\n",
33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit "
33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Status qualifier data:\n");
33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_lhand_nv");
33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit));
33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3396d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
340765a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status_qual.word[0],
34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s "
34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "closed, port handle 0x%x\n",
34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as closed */
34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter where scsi command is issued
34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @unit: unit where command is sent to
34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @scsi_cmnd: scsi command to be sent
34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @timer: timer to be started when request is initiated
34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags for fsf_request
34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct zfcp_unit *unit,
34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct scsi_cmnd * scsi_cmnd,
34702abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann			       int use_timer, int req_flags)
34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sbtype;
34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int real_bytes = 0;
34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mask;
34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not create FCP command request "
34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "for unit 0x%016Lx on port 0x%016Lx on "
34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s\n",
34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter));
34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_create;
34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3494059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_get(unit);
3495059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->unit = unit;
34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3497059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate FSF request with SCSI request (for look up on abort) */
34984eff4a36516d72e4f6ede901141214a7e05607e7Andreas Herrmann	scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id;
3499059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
3500059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate SCSI command with FSF request */
3501059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) scsi_cmnd;
35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FSF does not define the structure of the FCP_CMND IU */
35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set depending on data direction:
35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in SBALE (SB Type)
35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in QTCB
35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in FCP_CMND IU
35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (scsi_cmnd->sc_data_direction) {
35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_NONE:
35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME(qdio):
35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * what is the correct type for commands
35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * without 'real' data buffers?
35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_FROM_DEVICE:
35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->rddata = 1;
35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_TO_DEVICE:
35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_WRITE;
35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->wddata = 1;
35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_BIDIRECTIONAL:
35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * dummy, catch this condition earlier
35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in zfcp_scsi_queuecommand
35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_scsi_cmnd;
35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FC service class in QTCB (3 per default) */
354706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP_LUN in FCP_CMND IU in QTCB */
35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED;
35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set task attributes in FCP_CMND IU in QTCB */
35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely((scsi_cmnd->device->simple_tags) ||
35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (atomic_test_mask(mask, &unit->status))))
35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = UNTAGGED;
35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length
35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "additional FCP_CDB length is 0x%x "
35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(shifted right 2 bits)\n",
35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scsi_cmnd->cmd_len,
35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_cmnd_iu->add_fcp_cdb_length);
35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI CDB (including additional length, if any) to
35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FCP_CDB in FCP_CMND IU in QTCB
35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FCP CMND IU length in QTCB */
35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) +
35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* generate SBALEs from data buffer */
35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd);
35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(real_bytes < 0)) {
35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) {
35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG(
35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Data did not fit into available buffer(s), "
35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "waiting for more...\n");
35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: No truncation implemented but "
35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"required. Shutting down unit "
35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(adapter %s, port 0x%016Lx, "
35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx)\n",
35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun);
35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_shutdown(unit, 0);
35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_fit;
36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set length of FCP data length in FCP_CMND IU in QTCB */
36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Sending SCSI command:\n");
36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36112abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	if (use_timer)
36122abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
36132abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
36142abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send FCP command request "
36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send_failed;
36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, "
36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun);
36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_failed:
36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_fit:
36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_scsi_cmnd:
3634059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_put(unit);
36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_cmnd->host_scribble = NULL;
36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_create:
36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct zfcp_fsf_req *
36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  struct zfcp_unit *unit,
36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  u8 tm_flags, int req_flags)
36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FCP command (task "
36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) request for adapter %s, port "
36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      " 0x%016Lx, unit 0x%016Lx.\n",
36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, unit->fcp_lun);
36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Used to decide on proper handler in the return path,
36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * could be either zfcp_fsf_send_fcp_command_task_handler or
36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * zfcp_fsf_send_fcp_command_task_management_handler */
36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * hold a pointer to the unit being target of this
36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * task management request
36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3679059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FSF related fields in QTCB */
36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
368506506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP related fields in FCP_CMND IU in QTCB */
36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		&(fsf_req->qtcb->bottom.io.fcp_cmnd);
36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->task_management_flags = tm_flags;
36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36992abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
37002abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) on adapter %s, port 0x%016Lx for "
37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit LUN 0x%016Lx\n",
37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "tm_flags=0x%x)\n",
37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun,
37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       tm_flags);
37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_handler
37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Send FCP Command
37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
3743059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = (struct zfcp_unit *) fsf_req->data;
37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3745059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = fsf_req->unit;
37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* go directly to calls of special handlers */
37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid\n",
37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit "
37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Status qualifier data:\n");
37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_uhand_nv");
37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_HANDLE_MISMATCH:
37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed "
37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unexpectedly. (adapter %s, port 0x%016Lx, "
37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx)\n",
37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->handle,
37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun);
37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("status qualifier:\n");
37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_hand_mis");
38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
380606506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
380706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
380806506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_unit(unit),
380906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_class_nsup");
38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCPLUN_NOT_VALID:
38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on "
38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s does not have correct unit "
38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"handle 0x%x\n",
38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->handle);
38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_fcp_lun_nv");
38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to "
38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx on port 0x%016Lx on "
38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s\n",	unit->fcp_lun, unit->port->wwpn,
38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_DIRECTION_INDICATOR_NOT_VALID:
38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("bug: Invalid data direction given for unit "
38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s "
38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(debug info %d)\n",
38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.io.data_direction);
38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_dir_ind_nv");
38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CMND_LENGTH_NOT_VALID:
38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL
38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("bug: An invalid control-data-block length field "
38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "was found in a command for unit 0x%016Lx on port "
38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "0x%016Lx on adapter %s " "(debug info %d)\n",
38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     unit->fcp_lun, unit->port->wwpn,
38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     zfcp_get_busid_by_unit(unit),
38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     fsf_req->qtcb->bottom.io.fcp_cmnd_length);
38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_cmd_len_nv");
38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3893d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, "
39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n",
39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, unit->fcp_lun);
39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
3904d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			| ZFCP_STATUS_FSFREQ_RETRY;
39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
391565a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann 			zfcp_test_link(unit->port);
39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME(hw) need proper specs for proper action */
39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* let scsi stack deal with retries and escalation */
39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
3925516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann 			    ("Unknown status qualifier 0x%x arrived.\n",
39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(fsf_req->adapter->erp_dbf, 0,
39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(u32));
39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3934516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_RSP_AVAILABLE:
39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof(u32));
39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) {
39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval =
39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    zfcp_fsf_send_fcp_command_task_management_handler(fsf_req);
39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req);
3956059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		fsf_req->unit = NULL;
3957059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		zfcp_unit_put(unit);
39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_handler
39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *scpnt;
39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *)
39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3981059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = fsf_req->unit;
39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
3984059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	scpnt = (struct scsi_cmnd *) fsf_req->data;
39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(!scpnt)) {
39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG
39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("Command with fsf_req %p is not associated to "
39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "a scsi command anymore. Aborted?\n", fsf_req);
39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME: (design) mid-layer should handle DID_ABORT like
39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        DID_SOFT_ERROR by retrying the request for devices
39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        that allow retries.
39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n");
39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_SOFT_ERROR);
39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_driver_byte(&scpnt->result, SUGGEST_RETRY);
39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_ERROR\n");
40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_ERROR);
40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set message byte of result in SCSI command */
40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= COMMAND_COMPLETE << 8;
40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte
40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of result in SCSI command
40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->scsi_status)) {
40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* DEBUG */
40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status for SCSI Command:\n");
40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      scpnt->cmnd, scpnt->cmd_len);
40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("SCSI status code 0x%x\n",
40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_iu->scsi_status);
40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu));
40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu),
40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_sns_len);
40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("rsp_len is valid\n");
40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fcp_rsp_info[3]) {
40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_GOOD:
40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ok, continue */
40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_TRACE("no failure or Task Management "
40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "Function complete\n");
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_OK);
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_LENGTH_MISMATCH:
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"length differs from the burst length. "
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s",
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_FIELD_INVALID:
40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* driver or hardware bug */
40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fields were incorrectly set up. "
40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s",
40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_RO_MISMATCH:
40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The FCP response code indicates "
40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that conflicting  values for the "
40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fibrechannel payload offset from the "
40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"header were found. "
40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s.\n",
40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: An invalid FCP response "
40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"code was detected for a command. "
40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s (debug info 0x%x)\n",
40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fcp_rsp_info[3]);
41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
41056f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for sense data */
41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = FSF_FCP_RSP_SIZE -
41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n",
41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sns_len);
41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n",
41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       SCSI_SENSE_BUFFERSIZE);
41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scpnt->result);
41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->cmnd, scpnt->cmd_len);
41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_rsp_iu->fcp_sns_len);
41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(&scpnt->sense_buffer,
41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->sense_buffer, sns_len);
41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for overrun */
41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) {
41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data overrun was detected for a command. "
41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for underrun */
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data underrun was detected for a command. "
41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scpnt->resid = fcp_rsp_iu->fcp_resid;
41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
41596f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			set_host_byte(&scpnt->result, DID_ERROR);
41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41658a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
4166ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req);
41678a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
4168ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req);
41698a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
4170ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req);
41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* cleanup pointer (need this especially for abort) */
41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* always call back */
41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags);
41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_management_handler
41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
4203059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fcp_rsp_info[3]) {
42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_GOOD:
42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ok, continue */
42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("no failure or Task Management "
42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "Function complete\n");
42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_UNSUPP:
42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is not supported on the target device "
42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s\n ",
42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP;
42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_FAILED:
42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"failed to complete successfully. "
42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s.\n",
42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An invalid FCP response "
42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"code was detected for a command. "
42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s "
42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_info[3]);
42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      skip_fsfstatus:
42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file
42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Initiator of the control file upload/download FSF requests
42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0           - FSF request is successfuly created and queued
42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EOPNOTSUPP - The FCP adapter does not have Control File support
42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL     - Invalid direction specified
42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -ENOMEM     - Insufficient memory
42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM      - Cannot create FSF request or place it in QDIO queue
42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file(struct zfcp_adapter *adapter,
42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_fsf_req **fsf_req_ptr,
42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 fsf_command,
42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 option,
42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_sg_list *sg_list)
42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
42721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
42731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req_flags = 0;
42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int direction;
42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4278aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) {
42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n",
42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EOPNOTSUPP;
42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_command) {
42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_WRITE;
42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((option != FSF_CFDC_OPTION_FULL_ACCESS) &&
42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS))
42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req_flags = ZFCP_WAIT_FOR_SBAL;
42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_UPLOAD_CONTROL_FILE:
42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_READ;
42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command);
43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     NULL, &lock_flags, &fsf_req);
43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FSF request for the "
43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter %s\n",
43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unlock_queue_lock;
43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= direction;
43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->option = option;
43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_list->count > 0) {
43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int bytes;
43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sg_list->sg, sg_list->count,
43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_MAX_SBALS_PER_REQ);
43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) {
43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO(
43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"error: Could not create sufficient number of "
43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"SBALS for an FSF request to the adapter %s\n",
43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -ENOMEM;
43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto free_fsf_req;
43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43382abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
43392abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("initiation of cfdc up/download failed"
43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s)\n",
43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto free_fsf_req;
43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the "
43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"adapter %s\n",
43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"download" : "upload",
43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(fsf_req->completion_wq,
43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_ptr = fsf_req;
43592abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	goto out;
43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_fsf_req:
43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_queue_lock:
43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file_handler
43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Handler of the control file upload/download FSF requests
43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0       - FSF request successfuly processed
43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EAGAIN - Operation has to be repeated because of a temporary problem
43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EACCES - There is no permission to execute an operation
43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM  - The control file is not in a right format
43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO    - There is a problem with the FCP adapter
43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL - Invalid operation
43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EFAULT - User space memory I/O operation fault
43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header = &fsf_req->qtcb->header;
43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support;
43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"The FSF request has been successfully completed "
44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"on the adapter %s\n",
44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_OPERATION_PARTIALLY_SUCCESSFUL:
44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (header->fsf_status_qual.word[0]) {
44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44096f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			case FSF_SQ_CFDC_HARDENED_ON_SE:
44106f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				ZFCP_LOG_NORMAL(
44116f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"CFDC on the adapter %s has being "
44126f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"hardened on primary and secondary SE\n",
44136f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter));
44146f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				break;
44156f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>
44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be saved on the SE\n",
44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2:
44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be copied to the secondary SE\n",
44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC could not be hardened "
44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on the adapter %s\n",
44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EAGAIN;
44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_AUTHORIZATION_FAILURE:
44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s does not accept privileged commands\n",
44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EACCES;
44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CFDC_ERROR_DETECTED:
44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Error at position %d in the CFDC, "
44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"CFDC is discarded by the adapter %s\n",
44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status_qual.word[0],
44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_UPDATE_ERROR:
44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s cannot harden the control file, "
44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"file is discarded\n",
44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_TOO_LARGE:
44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Control file is too large, file is discarded "
44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"by the adapter %s\n",
44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_CONFLICT_DETECTED:
44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been discarded by the adapter %s, "
44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"because activation would impact "
44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONFLICTS_OVERRULED:
44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been activated on the adapter %s, "
44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"but activation has impacted "
44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, "
45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"op_subtype=0x%x)\n",
45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bottom->operation_subtype);
45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown/unexpected FSF status 0x%08x "
45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"was presented on the adapter %s\n",
45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status,
45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval");
45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_check(unsigned long *flags,
45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct zfcp_qdio_queue *queue, int needed)
45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&queue->queue_lock, *flags);
45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(atomic_read(&queue->free_count) >= needed))
45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&queue->queue_lock, *flags);
45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set qtcb pointer in fsf_req and initialize QTCB
45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
45524d284cac76d0bfebc42d76b428c4e44d921200a9Heiko Carstensstatic void
45538a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetyninzfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
4556fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.req_seq_no =
4557fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske			fsf_req->adapter->fsf_req_seq_no;
4558fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.req_id = fsf_req->req_id;
45591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
4560fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.qtcb_type =
4561fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske			fsf_qtcb_type[fsf_req->fsf_command];
45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
4563fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->header.req_handle = fsf_req->req_id;
45648a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter for which request queue is examined
45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags indicating whether to wait for needed SBAL or not
45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @lock_flags: lock_flags if queue_lock is taken
45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locks: lock adapter->request_queue->queue_lock on success
45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      unsigned long *lock_flags)
45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        long ret;
45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = wait_event_interruptible_timeout(adapter->request_wq,
45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1),
45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       ZFCP_SBAL_TIMEOUT);
45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ret)
45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1))
45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EIO;
45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_create
45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	create an FSF request at the specified adapter and
46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		setup common fields
46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	-ENOMEM if there was insufficient memory for a request
46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO if no qdio buffers could be allocate to the request
46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL/-EPERM on bug conditions in req_dequeue
46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              0 in success
46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note:        The created request is returned by reference.
46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:	lock of concerned request queue must not be held,
46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		but is held on completion (write, irqsave)
46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    mempool_t *pool, unsigned long *lock_flags,
46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    struct zfcp_fsf_req **fsf_req_p)
46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allocate new FSF request */
46241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(NULL == fsf_req)) {
46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
46271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "the outbound (send) queue.\n");
46281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_fsf_req;
46301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46328a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->adapter = adapter;
46338a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->fsf_command = fsf_cmd;
4634fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	INIT_LIST_HEAD(&fsf_req->list);
46352abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	init_timer(&fsf_req->timer);
46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* initialize waitqueue which may be used to wait on
46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this request completion */
46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&fsf_req->completion_wq);
46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
4642801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt        if (ret < 0)
46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_sbals;
4644801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt
4645801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	/* this is serialized (we are holding req_queue-lock of adapter) */
4646801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	if (adapter->req_no == 0)
4647801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt		adapter->req_no++;
4648801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	fsf_req->req_id = adapter->req_no++;
4649801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt
4650801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	zfcp_fsf_req_qtcb_init(fsf_req);
46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We hold queue_lock here. Check if QDIOUP is set and let request fail
46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if it is not set (see also *_open_qdio and *_close_qdio).
46551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
46561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags);
46591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EIO;
46601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_sbals;
46611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46638a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (fsf_req->qtcb) {
46648a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->seq_no = adapter->fsf_req_seq_no;
46658a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
46668a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	}
46671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_number = 1;
46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_first = req_queue->free_index;
46691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_curr = req_queue->free_index;
46701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        fsf_req->sbale_curr = 1;
46711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
46741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup common SBALE fields */
4679fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	sbale[0].addr = (void *) fsf_req->req_id;
46801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].addr = (void *) fsf_req->qtcb;
46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].length = sizeof(struct fsf_qtcb);
46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                       fsf_req->sbal_number, fsf_req->sbal_first);
46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_sbals:
46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* dequeue new FSF request previously enqueued */
46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_fsf_req:
46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&req_queue->queue_lock, *lock_flags);
46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_p = fsf_req;
47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_send
47051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	start transfer of FSF request via QDIO
47071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	0 - request transfer succesfully started
47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		!0 - start of request transfer failed
47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
47112abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmannstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
47141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue;
47151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
47168a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	int inc_seq_no;
47171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int new_distance_from_int;
4718fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	u64 dbg_tmp[2];
47191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
47201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
47221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue = &adapter->request_queue,
47231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME(debug): remove it later */
47261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0);
47271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags);
47281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n");
47291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
47301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      sbale[1].length);
47311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4732fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	/* put allocated FSF request into hash table */
4733fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock(&adapter->req_list_lock);
4734fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	zfcp_reqlist_add(adapter, fsf_req);
4735fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock(&adapter->req_list_lock);
47361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47378a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	inc_seq_no = (fsf_req->qtcb != NULL);
47388a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
47391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("request queue of adapter %s: "
47401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "next free SBAL is %i, %i free SBALs\n",
47411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
47421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       req_queue->free_index,
47431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       atomic_read(&req_queue->free_count));
47441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, "
47461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "index_in_queue=%i, count=%i, buffers=%p\n",
47471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
47481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       QDIO_FLAG_SYNC_OUTPUT,
47491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       0, fsf_req->sbal_first, fsf_req->sbal_number,
47501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       &req_queue->buffer[fsf_req->sbal_first]);
47511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
47531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * adjust the number of free SBALs in request queue as well as
47541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * position of first one
47551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
47561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_sub(fsf_req->sbal_number, &req_queue->free_count);
47571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count));
47581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index += fsf_req->sbal_number;	  /* increase */
47591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q;  /* wrap if needed */
47601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
47611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47628a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->issued = get_clock();
47638a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
47641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = do_QDIO(adapter->ccw_device,
47651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 QDIO_FLAG_SYNC_OUTPUT,
47661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
47671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4768fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	dbg_tmp[0] = (unsigned long) sbale[0].addr;
4769fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	dbg_tmp[1] = (u64) retval;
4770fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
4771fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
47721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval)) {
47731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Queues are down..... */
47741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
47752abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		del_timer(&fsf_req->timer);
4776fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		spin_lock(&adapter->req_list_lock);
4777ca2d02c2f9ea476062ae181eec60b8bcd97857d6Heiko Carstens		zfcp_reqlist_remove(adapter, fsf_req);
4778fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		spin_unlock(&adapter->req_list_lock);
4779fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		/* undo changes in request queue made for this request */
47801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_qdio_zero_sbals(req_queue->buffer,
47811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     fsf_req->sbal_first, fsf_req->sbal_number);
47821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_add(fsf_req->sbal_number, &req_queue->free_count);
4783fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		req_queue->free_index -= fsf_req->sbal_number;
47841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
47851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
4786fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		zfcp_erp_adapter_reopen(adapter, 0);
47871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
47881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->distance_from_int = new_distance_from_int;
47891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
47901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * increase FSF sequence counter -
47911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this must only be done for request successfully enqueued to
47921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * QDIO this rejected requests may be cleaned up by calling
47931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * routines  resulting in missing sequence counter values
47941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * otherwise,
47951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
47968a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
47971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Don't increase for unsolicited status */
47988a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		if (inc_seq_no)
47991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adapter->fsf_req_seq_no++;
48008a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
48011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* count FSF requests pending */
4802fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		atomic_inc(&adapter->reqs_active);
48031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
48041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
48051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
48061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ZFCP_LOG_AREA
4808