zfcp_fsf.c revision 3f0ca62add34010241db682e63bb68ba765bf4a9
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 *
8341fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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.
8641fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig *
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 *
19541fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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	/*
21741fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig	 * fsf_req may be deleted due to waking up functions, so
21841fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig	 * 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 *
26241fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26441fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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 *
64141fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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 *
85741fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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 *
109141fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * 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
1119951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
1120951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt			&unit->status)))
1121951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt		goto unit_blocked;
1122951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1127059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handle of request which should be aborted */
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11362abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
11372abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
1138951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt	if (!retval)
1139951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt		goto out;
1140951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
1141951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt unit_blocked:
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_abort_fcp_command_handler
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Abort FCP Command request
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
115541fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
1161059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit;
11628627533c115c546649693d68fed6a74762c47d51Christof Schmitt	union fsf_status_qual *fsf_stat_qual =
11638627533c115c546649693d68fed6a74762c47d51Christof Schmitt		&new_fsf_req->qtcb->header.fsf_status_qual;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1170059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) new_fsf_req->data;
1171059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (new_fsf_req->qtcb->header.fsf_status) {
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
11768627533c115c546649693d68fed6a74762c47d51Christof Schmitt		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv0");
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a port
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different). This is
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * fine.
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("Temporary port identifier 0x%x for "
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "port 0x%016Lx on adapter %s invalid. "
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "This may happen occasionally.\n",
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->handle,
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unit->port->wwpn,
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_unit(unit));
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("status qualifier:\n");
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_phand_nv1");
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_reopen(unit->port->adapter, 0);
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
12058627533c115c546649693d68fed6a74762c47d51Christof Schmitt		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv0");
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * In this case a command that was sent prior to a unit
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * reopen was aborted (handles are different).
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * This is fine.
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("Warning: Temporary LUN identifier 0x%x of LUN "
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "0x%016Lx on port 0x%016Lx on adapter %s is "
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "invalid. This may happen in rare cases. "
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     "Trying to re-establish link.\n",
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->handle,
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->fcp_lun,
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unit->port->wwpn,
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     zfcp_get_busid_by_unit(unit));
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG("Status qualifier data:\n");
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &new_fsf_req->qtcb->header.
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      fsf_status_qual,
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof (union fsf_status_qual));
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Let's hope this sorts out the mess */
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_s_lhand_nv1");
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_reopen(unit->port, 0);
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_no_exist");
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to "
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "be reopened\n", unit->port->wwpn,
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 2,
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_pboxed");
1249d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO(
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "unit 0x%016Lx on port 0x%016Lx on adapter %s needs "
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "to be reopened\n",
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        unit->fcp_lun, unit->port->wwpn,
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        zfcp_get_busid_by_unit(unit));
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
1261d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        | ZFCP_STATUS_FSFREQ_RETRY;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) {
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
127165a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* SCSI stack will escalate */
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 1,
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     new_fsf_req->qtcb->header.fsf_status_qual.word[0]);
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(new_fsf_req->adapter->erp_dbf, 0,
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&new_fsf_req->qtcb->header.
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_status_qual.word[0], sizeof (u32));
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_fsf_req->qtcb->header.fsf_status);
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(new_fsf_req->adapter->erp_dbf, 0,
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_inval:");
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(new_fsf_req->adapter->erp_dbf, 0,
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&new_fsf_req->qtcb->header.fsf_status,
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	one SBALE
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Two scatter-gather lists are passed, one for the reqeust and one for the
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * response.
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_use_one_sbal(struct scatterlist *req, int req_count,
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  struct scatterlist *resp, int resp_count)
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ((req_count == 1) &&
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(resp_count == 1) &&
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&req[0]) &
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 ((unsigned long) (zfcp_sg_to_address(&req[0]) +
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   req[0].length - 1) & PAGE_MASK)) &&
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                (((unsigned long) zfcp_sg_to_address(&resp[0]) &
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  PAGE_MASK) ==
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                 ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   resp[0].length - 1) & PAGE_MASK)));
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the request
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pool: pointer to memory pool, if non-null this pool is used to allocate
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	a struct zfcp_fsf_req
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @erp_action: pointer to erp_action, if non-null the Generic Service request
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	is sent within error recovery
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct zfcp_erp_action *erp_action)
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_fsf_req *fsf_req;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        unsigned long lock_flags;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = ct->port;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = port->adapter;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  pool, &lock_flags, &fsf_req);
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for "
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter: %s\n",
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (zfcp_use_one_sbal(ct->req, ct->req_count,
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              ct->resp, ct->resp_count)){
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* both request buffer and response buffer
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   fit into one sbale each */
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[2].length = ct->req[0].length;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].length = ct->resp[0].length;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
1380aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	} else if (adapter->adapter_features &
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* try to use chained SBALs */
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->req, ct->req_count,
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.req_buf_length = bytes;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                bytes = zfcp_qdio_sbals_from_sg(fsf_req,
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                SBAL_FLAGS0_TYPE_WRITE_READ,
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ct->resp, ct->resp_count,
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                                ZFCP_MAX_SBALS_PER_CT_REQ);
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes <= 0) {
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        ZFCP_LOG_INFO("error: creation of CT request failed "
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "on adapter %s\n",
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      zfcp_get_busid_by_adapter(adapter));
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        if (bytes == 0)
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = -ENOMEM;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        else
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                ret = bytes;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        goto failed_send;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else {
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                /* reject send generic request */
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"error: microcode does not support chained SBALs,"
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        "CT request too big (adapter %s)\n",
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = -EOPNOTSUPP;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_send;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* settings in QTCB */
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = port->handle;
142806506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.support.service_class =
142906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_FC_SERVICE_CLASS_DEFAULT;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.support.timeout = ct->timeout;
1431059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann        fsf_req->data = (unsigned long) ct;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14338a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	zfcp_san_dbf_event_ct_request(fsf_req);
14348a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
14352abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	if (erp_action) {
14362abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		erp_action->fsf_req = fsf_req;
14372abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		fsf_req->erp_action = erp_action;
14382abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_erp_start_timer(fsf_req);
14392abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	} else
14402abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
14412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
14422abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	ret = zfcp_fsf_req_send(fsf_req);
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: initiation of CT request failed "
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(adapter %s, port 0x%016Lx)\n",
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter), port->wwpn);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n",
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter), port->wwpn);
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (erp_action != NULL) {
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                erp_action->fsf_req = NULL;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        write_unlock_irqrestore(&adapter->request_queue.queue_lock,
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_ct_handler - handler for Generic Service requests
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1470059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the Generic Service request is passed using
1471059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_ct.
1472059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the CT request is called which is
1473059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_ct *send_ct;
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
1487059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_ct = (struct zfcp_send_ct *) fsf_req->data;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port = send_ct->port;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
14998a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_ct_response(fsf_req);
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                retval = 0;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
150406506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
150506506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
150606506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_port(port),
150706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* reopening link to port */
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_test_link(port);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                default:
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x "
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      "arrived.\n",
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send generic service "
15371d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"command (adapter %s, port d_id=0x%06x)\n",
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_port(port), port->d_id);
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GENERIC_COMMAND_REJECTED:
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("generic service command rejected "
15591d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id=0x%06x)\n",
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej");
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_HANDLE_NOT_VALID:
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port "
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "0x%016Lx on adapter %s invalid. This may "
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "happen occasionally.\n", port->handle,
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn, zfcp_get_busid_by_port(port));
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("status qualifier:\n");
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv");
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(adapter, 0);
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("port needs to be reopened "
15851d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id=0x%06x)\n",
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port), port->d_id);
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
1588d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    | ZFCP_STATUS_FSFREQ_RETRY;
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* following states should never occure, all cases avoided
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   in zfcp_fsf_send_ct - but who knows ... */
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("payload size mismatch (adapter: %s, "
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d, resp_buf_length=%d)\n",
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("request size too large (adapter: %s, "
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "req_buf_length=%d)\n",
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length);
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("response size too large (adapter: %s, "
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->resp_buf_length);
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       default:
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n", header->fsf_status);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:");
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ct->status = retval;
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (send_ct->handler != NULL)
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @els: pointer to struct zfcp_send_els which contains all needed data for
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the command.
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_els(struct zfcp_send_els *els)
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
165213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	u32 d_id;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int bytes;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = els->d_id;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = els->adapter;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ZFCP_REQ_AUTO_CLEANUP,
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  NULL, &lock_flags, &fsf_req);
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ZFCP_LOG_INFO("error: creation of ELS request failed "
16661d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter %s, port d_id: 0x%06x)\n",
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              zfcp_get_busid_by_adapter(adapter), d_id);
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_req;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16713f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
16723f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt			&els->port->status))) {
16733f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt		ret = -EBUSY;
16743f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt		goto port_blocked;
16753f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt	}
16763f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt
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
17583f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt port_blocked:
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_send:
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req:
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return ret;
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_els_handler - handler for ELS commands
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1774059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Data specific for the ELS command is passed using
1775059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * fsf_req->data. There we find the pointer to struct zfcp_send_els.
1776059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * Usually a specific handler for the ELS command is called which is
1777059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann * found in this structure.
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
178313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	u32 d_id;
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_send_els *send_els;
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1790059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	send_els = (struct zfcp_send_els *) fsf_req->data;
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = send_els->adapter;
179264b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann	port = send_els->port;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d_id = send_els->d_id;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18038a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		zfcp_san_dbf_event_els_response(fsf_req);
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
180806506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
180906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
181006506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_adapter(adapter),
181106506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup");
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest");
182264b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
182364b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval =
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      (struct zfcp_ls_rjt_par *)
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      &header->fsf_status_qual.word[2]);
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry");
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n",
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      header->fsf_status_qual.word[0]);
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(char*)header->fsf_status_qual.word, 16);
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("ELS has been rejected because command filter "
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "prohibited sending "
18491d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			      "(adapter: %s, port d_id: 0x%06x)\n",
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter), d_id);
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"ELS request size and ELS response size must be either "
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"both 0, or both greater than 0 "
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n",
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length,
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS request buffer, "
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS request data "
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, req_buf_length=%d)\n",
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->req_buf_length);
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO(
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Length of the ELS response buffer, "
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"specified in QTCB bottom, "
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"exceeds the size of the buffers "
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"that have been allocated for ELS response data "
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, resp_buf_length=%d)\n",
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->resp_buf_length);
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, avoided in zfcp_fsf_send_els */
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, "
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "resp_buf_length=%d)\n",
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      bottom->req_buf_length, bottom->resp_buf_length);
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
18971d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt				"(adapter %s, port d_id=0x%06x)\n",
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter), d_id);
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (port != NULL)
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_access_denied(port);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown FSF Status was presented "
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"(adapter: %s, fsf_status=0x%08x)\n",
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter),
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status);
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval");
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_els->status = retval;
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1934aa551daf5cc6fb6c6e09bb993737f9cd46dc7145Heiko Carstens	if (send_els->handler)
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
19442abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
194552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
194752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	int retval;
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
195052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	retval = zfcp_fsf_req_create(adapter,
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_EXCHANGE_CONFIG_DATA,
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_REQ_AUTO_CLEANUP,
195352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				     adapter->pool.fsf_req_erp,
19542abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
195552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval) {
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create exchange configuration "
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "data request for adapter %s.\n",
195852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
195952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
196052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig					lock_flags);
196152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return retval;
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19642abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
196552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
196652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19682abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.config.feature_selection =
1969aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_CFDC |
1970aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_LUN_SHARING |
19719eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			FSF_FEATURE_NOTIFICATION_LOST |
1972aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_UPDATE_ALERT;
19732abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
19742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19762abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
19772abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
197852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
197952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				lock_flags);
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
198152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: Could not send exchange configuration "
198252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "data command on the adapter %s\n",
198352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
19842abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
198752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	else
198852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_DEBUG("exchange configuration data request initiated "
198952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			       "(adapter %s)\n",
199052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			       zfcp_get_busid_by_adapter(adapter));
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
199352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schilligint
199652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schilligzfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
199752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				struct fsf_qtcb_bottom_config *data)
199852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
199952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	volatile struct qdio_buffer_element *sbale;
200052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_fsf_req *fsf_req;
200152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	unsigned long lock_flags;
200252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	int retval;
200352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
200452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	/* setup new FSF request */
200552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
200652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				     0, NULL, &lock_flags, &fsf_req);
200752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval) {
200852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: Could not create exchange configuration "
200952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "data request for adapter %s.\n",
201052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
201152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
201252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig					lock_flags);
201352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return retval;
201452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
201552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
201652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
201752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
201852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
201952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
202052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	fsf_req->qtcb->bottom.config.feature_selection =
202152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_CFDC |
202252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_LUN_SHARING |
202352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_NOTIFICATION_LOST |
202452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_UPDATE_ALERT;
202552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
202652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
202752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		fsf_req->data = (unsigned long) data;
202852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
202952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
203052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	retval = zfcp_fsf_req_send(fsf_req);
203152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	write_unlock_irqrestore(&adapter->request_queue.queue_lock,
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
203352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval)
203452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: Could not send exchange configuration "
203552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "data command on the adapter %s\n",
203652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
203752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	else
203852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		wait_event(fsf_req->completion_wq,
203952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
204052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
204152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	zfcp_fsf_req_free(fsf_req);
204252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_config_evaluate
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: fsf_req which belongs to xchg config data request
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1)
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns: -EIO on error, 0 otherwise
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
205813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann	struct Scsi_Host *shost = adapter->scsi_host;
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.config;
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n",
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       bottom->low_qtcb_version, bottom->high_qtcb_version);
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter->fsf_lic_version = bottom->lic_version;
2064aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	adapter->adapter_features = bottom->adapter_features;
2065aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	adapter->connection_features = bottom->connection_features;
20666f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwpn = 0;
20676f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_wwnn = 0;
20686f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>	adapter->peer_d_id = 0;
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xchg_ok) {
207152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
207252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		if (fsf_req->data)
207352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data,
207452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				bottom, sizeof (struct fsf_qtcb_bottom_config));
207552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
207613e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
207713e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
207813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
207913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_speed(shost) = bottom->fc_link_speed;
208052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		fc_host_supported_classes(shost) =
208152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				FC_COS_CLASS2 | FC_COS_CLASS3;
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = bottom->adapter_type;
2083ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		if (fc_host_permanent_port_name(shost) == -1)
2084ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_permanent_port_name(shost) =
2085ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann				fc_host_port_name(shost);
2086ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		if (bottom->fc_topology == FSF_TOPO_P2P) {
2087ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
2088ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_wwpn = bottom->plogi_payload.wwpn;
2089ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			adapter->peer_wwnn = bottom->plogi_payload.wwnn;
2090ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_PTP;
2091ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		} else if (bottom->fc_topology == FSF_TOPO_FABRIC)
2092ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
2093ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		else if (bottom->fc_topology == FSF_TOPO_AL)
2094ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
2095ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		else
2096ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann			fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
209813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_node_name(shost) = 0;
209913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_name(shost) = 0;
210013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_port_id(shost) = 0;
210113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
2102ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hydra_version = 0;
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2106aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adapter->hardware_version = bottom->hardware_version;
210813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		memcpy(fc_host_serial_number(shost), bottom->serial_number,
210913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		       min(FC_SERIAL_NUMBER_SIZE, 17));
211013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		EBCASC(fc_host_serial_number(shost),
211113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann		       min(FC_SERIAL_NUMBER_SIZE, 17));
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	ZFCP_LOG_NORMAL("The adapter %s reported the following "
211552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			"characteristics:\n"
211613e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"WWNN 0x%016Lx, "
211713e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"WWPN 0x%016Lx, "
21181d589edf9eeb60c9c8e62753d05cf4c8e094e5a7Christof Schmitt			"S_ID 0x%06x,\n"
211913e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"adapter version 0x%x, "
212013e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"LIC version 0x%x, "
212113e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			"FC link speed %d Gb/s\n",
212213e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			zfcp_get_busid_by_adapter(adapter),
212313e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			(wwn_t) fc_host_node_name(shost),
212413e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			(wwn_t) fc_host_port_name(shost),
212513e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			fc_host_port_id(shost),
212613e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			adapter->hydra_version,
212713e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			adapter->fsf_lic_version,
212813e1e1f08c1c098c7574c1fa72bd8c67792dc89bAndreas Herrmann			fc_host_speed(shost));
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports newer control block "
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions in comparison to this device "
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"driver (try updated device driver)\n",
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "low_qtcb_ver");
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("error: the adapter %s "
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"only supports older control block "
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"versions than this device driver uses"
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(consider a microcode upgrade)\n",
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "high_qtcb_ver");
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
215252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig/**
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_exchange_config_data_handler
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Exchange Configuration Data command
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_config *bottom;
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
2164aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	struct fsf_qtcb *qtcb = fsf_req->qtcb;
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2169aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (qtcb->header.fsf_status) {
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2175ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		switch (fc_host_port_type(adapter->scsi_host)) {
2176ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_PTP:
21776f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
21786f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"configuration detected at adapter %s\n"
21796f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"Peer WWNN 0x%016llx, "
21806f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer WWPN 0x%016llx, "
21816f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"peer d_id 0x%06x\n",
21826f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter),
21836f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwnn,
21846f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_wwpn,
21856f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					adapter->peer_d_id);
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
218752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig					"top-p-to-p");
21886f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			break;
2189ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_NLPORT:
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"topology detected at adapter %s "
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"unsupported, shutting down adapter\n",
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "top-al");
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
2198ad757cdfd2a40c9d5310d00f24427525788341cdAndreas Herrmann		case FC_PORTTYPE_NPORT:
2199aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
220052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig					"network detected at adapter %s.\n",
220152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig					zfcp_get_busid_by_adapter(adapter));
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"reported by the exchange "
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"configuration command for "
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"the adapter %s is not "
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"of a type known to the zfcp "
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"driver, shutting down adapter\n",
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "unknown-topo");
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2216aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		bottom = &qtcb->bottom.config;
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"allowed by the adapter %s "
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is lower than the minimum "
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"required by the driver (%ld bytes).\n",
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bottom->max_qtcb_size,
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter),
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct fsf_qtcb));
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "qtcb-size");
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_event(fsf_req->adapter->erp_dbf, 0,
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    &bottom->max_qtcb_size, sizeof (u32));
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_adapter_shutdown(adapter, 0);
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&adapter->status);
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "xchg-inco");
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
224152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
224252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				&adapter->status);
2243aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
2244aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		zfcp_fsf_link_down_info_eval(adapter,
2245aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			&qtcb->header.fsf_status_qual.link_down_info);
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_event(fsf_req->adapter->erp_dbf, 0,
225052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			    &fsf_req->qtcb->header.fsf_status, sizeof(u32));
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(adapter, 0);
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
2259aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * @erp_action: ERP action for the adapter for which port data is requested
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
226252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schilligzfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
226552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_fsf_req *fsf_req;
226652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
22672abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	unsigned long lock_flags;
226852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	int retval;
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2270aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: exchange port data "
227252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "command not supported by adapter %s\n",
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
227452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
227552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
227952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				     ZFCP_REQ_AUTO_CLEANUP,
228052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				     adapter->pool.fsf_req_erp,
228152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				     &lock_flags, &fsf_req);
228252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval) {
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
228452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "exchange port data request for"
228552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "the adapter %s.\n",
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
22892448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		return retval;
2290aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
2291aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
229352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
229452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	erp_action->fsf_req = fsf_req;
229752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	fsf_req->erp_action = erp_action;
229852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	zfcp_erp_start_timer(fsf_req);
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23002abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
230152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
230252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an exchange port data "
230552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "command on the adapter %s\n",
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
230852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		erp_action->fsf_req = NULL;
230952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
231052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	else
231152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_DEBUG("exchange port data request initiated "
231252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			       "(adapter %s)\n",
231352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			       zfcp_get_busid_by_adapter(adapter));
231452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
231552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
231652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
231752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
231852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig/**
231952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig * zfcp_fsf_exchange_port_data_sync - request information about local port
232052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig * and wait until information is ready
232152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig */
232252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schilligint
232352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schilligzfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
232452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				struct fsf_qtcb_bottom_port *data)
232552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
232652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	volatile struct qdio_buffer_element *sbale;
232752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_fsf_req *fsf_req;
232852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	unsigned long lock_flags;
232952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	int retval;
233052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
233152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
233252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: exchange port data "
233352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "command not supported by adapter %s\n",
233452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
233552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
233652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
233752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
233852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	/* setup new FSF request */
233952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
234052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig				0, NULL, &lock_flags, &fsf_req);
234152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval) {
234252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
234352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "exchange port data request for"
234452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "the adapter %s.\n",
234552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lock_flags);
23482448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		return retval;
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
235152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
235252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		fsf_req->data = (unsigned long) data;
235352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
235452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
235552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
235652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
235752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
235852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
235952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	retval = zfcp_fsf_req_send(fsf_req);
23602448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
236252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (retval)
236352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		ZFCP_LOG_INFO("error: Could not send an exchange port data "
236452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      "command on the adapter %s\n",
236552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			      zfcp_get_busid_by_adapter(adapter));
236652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	else
23672448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann		wait_event(fsf_req->completion_wq,
23682448c45965870ca9cfdb66388b4fcc93f1e12bb7Andreas Herrmann			   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
236952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
237052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	zfcp_fsf_req_free(fsf_req);
237152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23752f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann/**
23762f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * zfcp_fsf_exchange_port_evaluate
23772f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * @fsf_req: fsf_req which belongs to xchg port data request
23782f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1)
23792f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann */
23802f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmannstatic void
23812f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmannzfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
23822f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann{
23832f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct zfcp_adapter *adapter;
238452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct fsf_qtcb_bottom_port *bottom;
23852f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct Scsi_Host *shost;
23862f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
23872f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	adapter = fsf_req->adapter;
238852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	bottom = &fsf_req->qtcb->bottom.port;
23892f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	shost = adapter->scsi_host;
23902f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
239152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (fsf_req->data)
239252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom,
239352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			sizeof(struct fsf_qtcb_bottom_port));
23942f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
23952f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
23962f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		fc_host_permanent_port_name(shost) = bottom->wwpn;
23972f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	else
23982f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
23992f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
24002f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	fc_host_supported_speeds(shost) = bottom->supported_speed;
24012f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann}
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fsf_req: pointer to struct zfcp_fsf_req
24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24102f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct zfcp_adapter *adapter;
24112f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	struct fsf_qtcb *qtcb;
24122f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann
24132f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	adapter = fsf_req->adapter;
24142f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann	qtcb = fsf_req->qtcb;
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2419aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (qtcb->header.fsf_status) {
24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
24212f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		zfcp_fsf_exchange_port_evaluate(fsf_req, 1);
2422aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
2423aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
2424aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
24252f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		zfcp_fsf_exchange_port_evaluate(fsf_req, 0);
2426aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
2427aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		zfcp_fsf_link_down_info_eval(adapter,
2428aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			&qtcb->header.fsf_status_qual.link_down_info);
24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        default:
2431aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		debug_text_event(adapter->erp_dbf, 0, "xchg-port-ng");
2432aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		debug_event(adapter->erp_dbf, 0,
24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &fsf_req->qtcb->header.fsf_status, sizeof(u32));
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
244141fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * purpose:
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of initiated FSF request
244441fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig *		NULL - request could not be initiated
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
24502abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_PORT_WITH_DID,
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
24592abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open port request "
24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24682abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
24742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
24752abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
24762abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24782abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
24792abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send open port request for "
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
24852abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("open port request initiated "
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s,  port 0x%016Lx)\n",
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_port_handler
25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open Port command
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
250541fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2516059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s "
25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is already open.\n",
25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_popen");
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This is a bug, however operation should continue normally
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * if it is simply ignored
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx "
25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"on adapter %s\n",
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The FSF adapter is out of resources. "
25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The remote port 0x%016Lx on adapter %s "
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "could not be opened. Disabling it.\n",
25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_ports");
25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_failed(port);
25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("The remote port 0x%016Lx on "
25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s could not be opened. "
25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"Disabling it.\n",
25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwpn,
25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_port(port));
25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     "fsf_sq_no_retry");
25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_erp_port_failed(port);
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0],
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save port handle assigned by FSF */
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s "
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "was opened, it's port handle is 0x%x\n",
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port),
26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle);
26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark port as open */
26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
2621d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
2622d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
2623d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (fsf_req->qtcb->bottom.support.els1_length <
264475bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner			    sizeof (struct fsf_plogi)) {
26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO(
26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"warning: insufficient length of "
26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"PLOGI payload (%i)\n",
26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fsf_req->qtcb->bottom.support.els1_length);
26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debug_text_event(fsf_req->adapter->erp_dbf, 0,
26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 "fsf_s_short_plogi:");
26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* skip sanity check and assume wwpn is ok */
26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (plogi->serv_param.wwpn != port->wwpn) {
26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ZFCP_LOG_INFO("warning: d_id of port "
26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "0x%016Lx changed during "
26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      "open\n", port->wwpn);
26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debug_text_event(
26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						fsf_req->adapter->erp_dbf, 0,
26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fsf_s_did_change:");
26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					atomic_clear_mask(
26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_STATUS_PORT_DID_DID,
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&port->status);
266375bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner				} else {
26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port->wwnn = plogi->serv_param.wwnn;
266575bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner					zfcp_plogi_evaluate(port, plogi);
266675bfc2837bbcc329193d51e8b7115184b78beae0Ralph Wuerthner				}
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should never occure, subtype not set in zfcp_fsf_open_port */
26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, "
26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "op_subtype=0x%x)\n",
26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.support.operation_subtype);
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port
26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close port"
26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
27072abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PORT,
27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
27162abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create a close port request "
27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s.\n",
27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27252abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
27302abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
27312abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
27322abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
27332abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
27342abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
27352abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
27362abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
27372abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close port request for "
27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "port 0x%016Lx on adapter %s.\n",
27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
27432abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close port request initiated "
27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_port_handler
27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Port FSF command
27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may happen "
27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "occasionally.\n", port->handle,
27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn, zfcp_get_busid_by_port(port));
27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Note: FSF has actually closed the port in this case.
27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The status code is just daft. Fingers crossed for a change
27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, "
28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "port handle 0x%x\n", port->wwpn,
28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_modify_port_status(port,
28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port
28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     submit FSF command "close physical port"
28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     address of initiated FSF request
28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              NULL - request could not be initiated
28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
28412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
28422abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	unsigned long lock_flags;
28432abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	int retval = 0;
28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_PHYSICAL_PORT,
28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
28502abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close physical port "
28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28602abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* mark port as being closed */
28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&erp_action->port->status);
28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* save a pointer to this port */
28682abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->port;
28692abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
28702abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
28712abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
28722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
28732abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
28742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send close physical port "
28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "request (adapter %s, port 0x%016Lx)\n",
28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn);
28802abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("close physical port request initiated "
28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx)\n",
28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn);
28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_physical_port_handler
28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close Physical Port FSF command
28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req)
29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_port *port;
29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	port = (struct zfcp_port *) fsf_req->data;
29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change port status in our bookkeeping */
29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid"
29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s, port 0x%016Lx). "
29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally.\n",
29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->handle,
29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_port(port),
29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      port->wwpn);
29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(port->adapter, 0);
29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot close "
29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"physical port 0x%016Lx on adapter %s\n",
29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port->wwpn, zfcp_get_busid_by_port(port));
29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       			ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_access_denied(port);
29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter "
29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s needs to be reopened but it was attempted "
29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "to close it physically.\n",
29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port));
29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_pboxed");
2968d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(port);
29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This will now be escalated by ERP */
29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status_qual.word[0], sizeof (u32));
29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s "
30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "physically closed, port handle 0x%x\n",
30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       port->wwpn,
30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_port(port), port->handle);
30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit
30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions:	This routine does not check whether the associated
30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		remote port has already been opened. This should be
30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		done by calling routines. Otherwise some status
30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		may be presented by FSF
30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
30452abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_OPEN_LUN,
30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
30542abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create open unit request for "
30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->port->wwpn,
30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30642abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30682abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
30692abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->bottom.support.fcp_lun =	erp_action->unit->fcp_lun;
3070aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
30712abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		fsf_req->qtcb->bottom.support.option =
307206506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			FSF_OPEN_LUN_SUPPRESS_BOXING;
30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
30742abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->unit;
30752abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
30762abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30782abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
30792abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(erp_action->fsf_req);
30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an open unit request "
30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on the adapter %s, port 0x%016Lx for "
30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx\n",
30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter),
30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun);
30872abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, "
30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_open_unit_handler
31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Open LUN command
31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
310741fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_queue_designator *queue_designator;
31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
3119aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	queue_designator = &header->fsf_status_qual.fsf_queue_designator;
31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
3134b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x "
31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "for port 0x%016Lx on adapter %s invalid "
31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "This may happen occasionally\n",
31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_ph_nv");
31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on "
31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s twice.\n",
31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, zfcp_get_busid_by_unit(unit));
31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(adapter->erp_dbf, 0,
31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_uopen");
31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on "
31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"remote port 0x%016Lx on adapter %s\n",
31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun, unit->port->wwpn,
31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access");
31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
3197d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (header->fsf_status_qual.word[0] != 0) {
32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port "
32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"with WWPN 0x%Lx "
32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"connected to the adapter %s "
32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"is already in use in LPAR%d, CSS%d\n",
32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->hla,
32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					queue_designator->cssid);
32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[4];
32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[5];
32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the "
32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"remote port with WWPN 0x%Lx "
32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"connected to the adapter %s "
32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"is denied (%s rule %d)\n",
32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun,
32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_act_subtable_type[subtable],
32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rule);
32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 2,
32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_l_sh_vio");
32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: The adapter ran out of resources. "
32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "There is no handle (temporary port identifier) "
32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "available for unit 0x%016Lx on port 0x%016Lx "
32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s\n",
32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 1,
32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_max_units");
32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_failed(unit);
32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Re-establish link to port */
32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
326565a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 1,
32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(adapter->erp_dbf, 0,
32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(adapter->erp_dbf, 0,
32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save LUN handle assigned by FSF */
32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on "
33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s opened, port handle 0x%x\n",
33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as open */
33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
3307aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
3308aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
3309aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
3310aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
3311aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
3312aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
3313aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
3314aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
3315aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("read-only access for unit "
33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"(adapter %s, wwpn=0x%016Lx, "
33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"fcp_lun=0x%016Lx)\n",
33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						zfcp_get_busid_by_unit(unit),
33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->port->wwpn,
33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						unit->fcp_lun);
33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("exclusive access of read-only "
33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_failed(unit);
33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		ZFCP_LOG_NORMAL("shared access of read-write "
33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"unit not supported\n");
33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		zfcp_erp_unit_failed(unit);
33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_erp_unit_shutdown(unit, 0);
33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status);
33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(adapter->erp_dbf, 0, "fsf_s_inval:");
33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(adapter->erp_dbf, 0,
33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof (u32));
33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit
33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:
33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	address of fsf_req - request successfully initiated
337041fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig *		NULL -
33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumptions: This routine does not check whether the associated
33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              remote port/lun has already been opened. This should be
33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              done by calling routines. Otherwise some status
33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              may be presented by FSF
33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
33812abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	struct zfcp_fsf_req *fsf_req;
33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(erp_action->adapter,
33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     FSF_QTCB_CLOSE_LUN,
33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     erp_action->adapter->pool.fsf_req_erp,
33902abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann				     &lock_flags, &fsf_req);
33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create close unit request for "
33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34002abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34042abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.port_handle = erp_action->port->handle;
34052abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
34072abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->data = (unsigned long) erp_action->unit;
34082abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	fsf_req->erp_action = erp_action;
34092abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	erp_action->fsf_req = fsf_req;
34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34112abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_erp_start_timer(fsf_req);
34122abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(erp_action->fsf_req);
34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send a close unit request for "
34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n",
34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->unit->fcp_lun,
34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      erp_action->port->wwpn,
34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(erp_action->adapter));
34192abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_req_free(fsf_req);
34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, "
34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(erp_action->adapter),
34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       erp_action->port->wwpn, erp_action->unit->fcp_lun);
34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lock_flags);
34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_close_unit_handler
34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     is called for finished Close LUN FSF command
34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:
34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3447059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	unit = (struct zfcp_unit *) fsf_req->data;
34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't change unit status in our bookkeeping */
34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_req->qtcb->header.fsf_status) {
34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid. This may "
34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "happen in rare circumstances\n",
34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit "
34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Status qualifier data:\n");
34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &fsf_req->qtcb->header.fsf_status_qual,
34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_lhand_nv");
34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit));
34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3498d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
350965a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ERP strategy will escalate */
35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ("bug: Wrong status qualifier 0x%x arrived.\n",
35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     fsf_req->qtcb->header.fsf_status_qual.word[0]);
35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(
35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->adapter->erp_dbf, 0,
35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status_qual.word[0],
35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s "
35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "closed, port handle 0x%x\n",
35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_unit(unit),
35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->handle);
35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* mark unit as closed */
35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented "
35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fsf_req->qtcb->header.fsf_status);
35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&fsf_req->qtcb->header.fsf_status,
35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof (u32));
35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter where scsi command is issued
35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @unit: unit where command is sent to
35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @scsi_cmnd: scsi command to be sent
35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @timer: timer to be started when request is initiated
35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags for fsf_request
35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct zfcp_unit *unit,
35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct scsi_cmnd * scsi_cmnd,
35722abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann			       int use_timer, int req_flags)
35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sbtype;
35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int real_bytes = 0;
35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mask;
35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not create FCP command request "
35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "for unit 0x%016Lx on port 0x%016Lx on "
35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "adapter %s\n",
35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->fcp_lun,
35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn,
35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       zfcp_get_busid_by_adapter(adapter));
35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_req_create;
35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3596059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_get(unit);
3597059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->unit = unit;
35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3599059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate FSF request with SCSI request (for look up on abort) */
36004eff4a36516d72e4f6ede901141214a7e05607e7Andreas Herrmann	scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id;
3601059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
3602059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	/* associate SCSI command with FSF request */
3603059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) scsi_cmnd;
36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set handles of unit and its parent port in QTCB */
36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FSF does not define the structure of the FCP_CMND IU */
36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set depending on data direction:
36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in SBALE (SB Type)
36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in QTCB
36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      data direction bits in FCP_CMND IU
36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (scsi_cmnd->sc_data_direction) {
36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_NONE:
36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME(qdio):
36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * what is the correct type for commands
36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * without 'real' data buffers?
36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_FROM_DEVICE:
36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_READ;
36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->rddata = 1;
36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_TO_DEVICE:
36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbtype = SBAL_FLAGS0_TYPE_WRITE;
36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->wddata = 1;
36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DMA_BIDIRECTIONAL:
36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * dummy, catch this condition earlier
36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in zfcp_scsi_queuecommand
36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_scsi_cmnd;
36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FC service class in QTCB (3 per default) */
364906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP_LUN in FCP_CMND IU in QTCB */
36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED;
36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set task attributes in FCP_CMND IU in QTCB */
36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely((scsi_cmnd->device->simple_tags) ||
36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (atomic_test_mask(mask, &unit->status))))
36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->task_attribute = UNTAGGED;
36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length
36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "additional FCP_CDB length is 0x%x "
36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "(shifted right 2 bits)\n",
36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scsi_cmnd->cmd_len,
36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_cmnd_iu->add_fcp_cdb_length);
36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI CDB (including additional length, if any) to
36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FCP_CDB in FCP_CMND IU in QTCB
36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FCP CMND IU length in QTCB */
36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) +
36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* generate SBALEs from data buffer */
36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd);
36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(real_bytes < 0)) {
36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) {
36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_DEBUG(
36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"Data did not fit into available buffer(s), "
36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "waiting for more...\n");
36912282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt			retval = -EIO;
36922282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt		} else {
36932282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt			ZFCP_LOG_NORMAL("error: No truncation implemented but "
36942282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					"required. Shutting down unit "
36952282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					"(adapter %s, port 0x%016Lx, "
36962282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					"unit 0x%016Lx)\n",
36972282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					zfcp_get_busid_by_unit(unit),
36982282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					unit->port->wwpn,
36992282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt					unit->fcp_lun);
37002282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt			zfcp_erp_unit_shutdown(unit, 0);
37012282f658914e316ca32fd120fded130d1c0e26e4Christof Schmitt			retval = -EINVAL;
37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_fit;
37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set length of FCP data length in FCP_CMND IU in QTCB */
37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("Sending SCSI command:\n");
37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37132abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	if (use_timer)
37142abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
37152abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
37162abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval < 0)) {
37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send FCP command request "
37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send_failed;
37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, "
37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "port 0x%016Lx, unit 0x%016Lx)\n",
37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun);
37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_failed:
37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_fit:
37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_scsi_cmnd:
3736059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	zfcp_unit_put(unit);
37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_cmnd->host_scribble = NULL;
37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_req_create:
37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct zfcp_fsf_req *
37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  struct zfcp_unit *unit,
37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  u8 tm_flags, int req_flags)
37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu;
37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup new FSF request */
37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     adapter->pool.fsf_req_scsi,
37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     &lock_flags, &fsf_req);
37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FCP command (task "
37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) request for adapter %s, port "
37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      " 0x%016Lx, unit 0x%016Lx.\n",
37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, unit->fcp_lun);
37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Used to decide on proper handler in the return path,
37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * could be either zfcp_fsf_send_fcp_command_task_handler or
37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * zfcp_fsf_send_fcp_command_task_management_handler */
37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * hold a pointer to the unit being target of this
37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * task management request
37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3781059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	fsf_req->data = (unsigned long) unit;
37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FSF related fields in QTCB */
37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.lun_handle = unit->handle;
37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->header.port_handle = unit->port->handle;
37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
378706506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->qtcb->bottom.io.fcp_cmnd_length =
37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set FCP related fields in FCP_CMND IU in QTCB */
37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu = (struct fcp_cmnd_iu *)
37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		&(fsf_req->qtcb->bottom.io.fcp_cmnd);
37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fcp_cmnd_iu->task_management_flags = tm_flags;
38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38012abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
38022abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "management) on adapter %s, port 0x%016Lx for "
38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit LUN 0x%016Lx\n",
38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter),
38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun);
38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_fsf_req_free(fsf_req);
38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req = NULL;
38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "tm_flags=0x%x)\n",
38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->port->wwpn,
38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unit->fcp_lun,
38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       tm_flags);
38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fsf_req;
38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_handler
38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	is called for finished Send FCP Command
38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
383241fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = -EINVAL;
38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header;
38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 subtable, rule, counter;
38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	header = &fsf_req->qtcb->header;
38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
3845059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = (struct zfcp_unit *) fsf_req->data;
38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3847059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		unit = fsf_req->unit;
38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* go directly to calls of special handlers */
38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* evaluate FSF status in QTCB */
38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port "
38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on adapter %s invalid\n",
38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->handle,
38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn, zfcp_get_busid_by_unit(unit));
38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_phand_nv");
38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit "
38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s is "
38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "invalid. This may happen occasionally.\n",
38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->handle,
38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit));
38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Status qualifier data:\n");
38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_uhand_nv");
38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_HANDLE_MISMATCH:
38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed "
38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unexpectedly. (adapter %s, port 0x%016Lx, "
38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx)\n",
38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->handle,
38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun);
38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("status qualifier:\n");
38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_hand_mis");
39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_reopen(unit->port->adapter, 0);
39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
390806506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann		ZFCP_LOG_INFO("error: adapter %s does not support fc "
390906506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      "class %d.\n",
391006506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      zfcp_get_busid_by_unit(unit),
391106506d00ec1a0d7d3b1dff59185af355ce29ac0aAndreas Herrmann			      ZFCP_FC_SERVICE_CLASS_DEFAULT);
39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_exception(fsf_req->adapter->erp_dbf, 0,
39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     "fsf_s_class_nsup");
39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCPLUN_NOT_VALID:
39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on "
39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s does not have correct unit "
39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"handle 0x%x\n",
39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->handle);
39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status qualifier:\n");
39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (char *) &header->fsf_status_qual,
39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof (union fsf_status_qual));
39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1,
39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_fcp_lun_nv");
39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_port_reopen(unit->port, 0);
39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to "
39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx on port 0x%016Lx on "
39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"adapter %s\n",	unit->fcp_lun, unit->port->wwpn,
39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (counter = 0; counter < 2; counter++) {
39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			subtable = header->fsf_status_qual.halfword[counter * 2];
39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rule = header->fsf_status_qual.halfword[counter * 2 + 1];
39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (subtable) {
39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_OS:
39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_SUBTABLE_LUN:
39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_INFO("Access denied (%s rule %d)\n",
39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_act_subtable_type[subtable], rule);
39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access");
39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_unit_access_denied(unit);
39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_DIRECTION_INDICATOR_NOT_VALID:
39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("bug: Invalid data direction given for unit "
39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "0x%016Lx on port 0x%016Lx on adapter %s "
39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(debug info %d)\n",
39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fsf_req->qtcb->bottom.io.data_direction);
39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_dir_ind_nv");
39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CMND_LENGTH_NOT_VALID:
39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL
39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("bug: An invalid control-data-block length field "
39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "was found in a command for unit 0x%016Lx on port "
39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "0x%016Lx on adapter %s " "(debug info %d)\n",
39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     unit->fcp_lun, unit->port->wwpn,
39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     zfcp_get_busid_by_unit(unit),
39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     fsf_req->qtcb->bottom.io.fcp_cmnd_length);
39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* stop operation for this adapter */
39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0,
39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "fsf_s_cmd_len_nv");
39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s "
39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "needs to be reopened\n",
39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unit->port->wwpn, zfcp_get_busid_by_unit(unit));
39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed");
3995d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_port_boxed(unit->port);
39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_STATUS_FSFREQ_RETRY;
39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, "
40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n",
40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn, unit->fcp_lun);
40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed");
4006d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		zfcp_erp_unit_boxed(unit);
40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			| ZFCP_STATUS_FSFREQ_RETRY;
40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* re-establish link to port */
40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ltest");
401765a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann 			zfcp_test_link(unit->port);
40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME(hw) need proper specs for proper action */
40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* let scsi stack deal with retries and escalation */
40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 1,
40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_ulp");
40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL
4027516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann 			    ("Unknown status qualifier 0x%x arrived.\n",
40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     header->fsf_status_qual.word[0]);
40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_text_event(fsf_req->adapter->erp_dbf, 0,
40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 "fsf_sq_inval:");
40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debug_exception(fsf_req->adapter->erp_dbf, 0,
40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&header->fsf_status_qual.word[0],
40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(u32));
40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4036516a4201bacfd61ea957039d6f47276ee9c32a0dAndreas Herrmann		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_RSP_AVAILABLE:
40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:");
40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&header->fsf_status, sizeof(u32));
40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) {
40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval =
40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    zfcp_fsf_send_fcp_command_task_management_handler(fsf_req);
40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req);
4058059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		fsf_req->unit = NULL;
4059059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann		zfcp_unit_put(unit);
40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_handler
40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
406941fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *scpnt;
40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *)
40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_cmnd);
40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4083059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = fsf_req->unit;
40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
4086059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	scpnt = (struct scsi_cmnd *) fsf_req->data;
40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(!scpnt)) {
40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG
40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ("Command with fsf_req %p is not associated to "
40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     "a scsi command anymore. Aborted?\n", fsf_req);
40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME: (design) mid-layer should handle DID_ABORT like
40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        DID_SOFT_ERROR by retrying the request for devices
40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *        that allow retries.
40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n");
40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_SOFT_ERROR);
41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_driver_byte(&scpnt->result, SUGGEST_RETRY);
41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("Setting DID_ERROR\n");
41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_host_byte(&scpnt->result, DID_ERROR);
41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set message byte of result in SCSI command */
41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= COMMAND_COMPLETE << 8;
41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte
41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of result in SCSI command
41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->scsi_status)) {
41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* DEBUG */
41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("status for SCSI Command:\n");
41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      scpnt->cmnd, scpnt->cmd_len);
41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("SCSI status code 0x%x\n",
41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_iu->scsi_status);
41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu));
41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu),
41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_sns_len);
41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("rsp_len is valid\n");
41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fcp_rsp_info[3]) {
41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_GOOD:
41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ok, continue */
41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_TRACE("no failure or Task Management "
41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "Function complete\n");
41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_OK);
41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_LENGTH_MISMATCH:
41431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"length differs from the burst length. "
41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s",
41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_FIELD_INVALID:
41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* driver or hardware bug */
41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: FCP response code indictates "
41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that the fibrechannel protocol data "
41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fields were incorrectly set up. "
41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s",
41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RSP_CODE_RO_MISMATCH:
41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* hardware bug */
41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: The FCP response code indicates "
41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"that conflicting  values for the "
41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"fibrechannel payload offset from the "
41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"header were found. "
41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on unit 0x%016Lx "
41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on port 0x%016Lx on adapter %s.\n",
41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit));
41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto skip_fsfstatus;
41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL("bug: An invalid FCP response "
41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"code was detected for a command. "
41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"The problem occured on the unit "
41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"0x%016Lx on port 0x%016Lx on "
41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"adapter %s (debug info 0x%x)\n",
41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->fcp_lun,
41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unit->port->wwpn,
42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_unit(unit),
42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					fcp_rsp_info[3]);
42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* dump SCSI CDB as prepared by zfcp */
42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      (char *) &fsf_req->qtcb->
42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_host_byte(&scpnt->result, DID_ERROR);
42076f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for sense data */
42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = FSF_FCP_RSP_SIZE -
42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n",
42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sns_len);
42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n",
42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       SCSI_SENSE_BUFFERSIZE);
42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       scpnt->result);
42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->cmnd, scpnt->cmd_len);
42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       fcp_rsp_iu->fcp_sns_len);
42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(&scpnt->sense_buffer,
42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (void *) &scpnt->sense_buffer, sns_len);
42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for overrun */
42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) {
42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data overrun was detected for a command. "
42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for underrun */
42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("A data underrun was detected for a command. "
42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. "
42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "The response data length is "
42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%d, the original length was %d.\n",
42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->fcp_lun,
42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unit->port->wwpn,
42551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_unit(unit),
42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      fcp_rsp_iu->fcp_resid,
42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42597936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
42607936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
42617936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		    scpnt->underflow)
42626f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			set_host_byte(&scpnt->result, DID_ERROR);
42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skip_fsfstatus:
42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42688a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
4269ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req);
42708a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
4271ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req);
42728a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
4273ed829ad607a9c334cea490d3a8c0f874153fb42dMaxim Shchetynin		zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req);
42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* cleanup pointer (need this especially for abort) */
42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* always call back */
42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags);
42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_send_fcp_command_task_management_handler
42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	evaluates FCP_RSP IU
42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
429741fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig * returns:
42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
43001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
43011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    &(fsf_req->qtcb->bottom.io.fcp_rsp);
43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
4306059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann	struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check FCP_RSP_INFO */
43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fcp_rsp_info[3]) {
43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_GOOD:
43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ok, continue */
43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("no failure or Task Management "
43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "Function complete\n");
43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_UNSUPP:
43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"is not supported on the target device "
43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s\n ",
43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP;
43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RSP_CODE_TASKMAN_FAILED:
43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: A reuested task management function "
43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"failed to complete successfully. "
43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s.\n",
43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit));
43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("bug: An invalid FCP response "
43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"code was detected for a command. "
43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unit 0x%016Lx, port 0x%016Lx, adapter %s "
43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"(debug info 0x%x)\n",
43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->fcp_lun,
43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unit->port->wwpn,
43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_unit(unit),
43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fcp_rsp_info[3]);
43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      skip_fsfstatus:
43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file
43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Initiator of the control file upload/download FSF requests
43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0           - FSF request is successfuly created and queued
43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EOPNOTSUPP - The FCP adapter does not have Control File support
43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL     - Invalid direction specified
43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -ENOMEM     - Insufficient memory
43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM      - Cannot create FSF request or place it in QDIO queue
43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file(struct zfcp_adapter *adapter,
43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_fsf_req **fsf_req_ptr,
43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 fsf_command,
43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      u32 option,
43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                      struct zfcp_sg_list *sg_list)
43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req;
43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom;
43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long lock_flags;
43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req_flags = 0;
43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int direction;
43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) {
43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n",
43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EOPNOTSUPP;
43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fsf_command) {
43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_WRITE;
43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((option != FSF_CFDC_OPTION_FULL_ACCESS) &&
43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS))
43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req_flags = ZFCP_WAIT_FOR_SBAL;
43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_QTCB_UPLOAD_CONTROL_FILE:
43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		direction = SBAL_FLAGS0_TYPE_READ;
43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command);
44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     NULL, &lock_flags, &fsf_req);
44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("error: Could not create FSF request for the "
44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "adapter %s\n",
44121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unlock_queue_lock;
44151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= direction;
44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom = &fsf_req->qtcb->bottom.support;
44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bottom->option = option;
44231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_list->count > 0) {
44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int bytes;
44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sg_list->sg, sg_list->count,
44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ZFCP_MAX_SBALS_PER_REQ);
44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) {
44311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_INFO(
44321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"error: Could not create sufficient number of "
44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"SBALS for an FSF request to the adapter %s\n",
44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter));
44351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -ENOMEM;
44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto free_fsf_req;
44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44412abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
44422abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	retval = zfcp_fsf_req_send(fsf_req);
44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_INFO("initiation of cfdc up/download failed"
44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "(adapter %s)\n",
44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      zfcp_get_busid_by_adapter(adapter));
44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
44481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto free_fsf_req;
44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the "
44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"adapter %s\n",
44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"download" : "upload",
44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(fsf_req->completion_wq,
44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
44601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_ptr = fsf_req;
44622abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	goto out;
44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_fsf_req:
44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_queue_lock:
44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_control_file_handler
44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:     Handler of the control file upload/download FSF requests
44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:     0       - FSF request successfuly processed
44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EAGAIN - Operation has to be repeated because of a temporary problem
44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EACCES - There is no permission to execute an operation
44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EPERM  - The control file is not in a right format
44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO    - There is a problem with the FCP adapter
44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL - Invalid operation
44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EFAULT - User space memory I/O operation fault
44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter = fsf_req->adapter;
44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_header *header = &fsf_req->qtcb->header;
44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support;
44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"The FSF request has been successfully completed "
45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"on the adapter %s\n",
45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_OPERATION_PARTIALLY_SUCCESSFUL:
45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) {
45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (header->fsf_status_qual.word[0]) {
45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45126f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			case FSF_SQ_CFDC_HARDENED_ON_SE:
45136f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				ZFCP_LOG_NORMAL(
45146f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"CFDC on the adapter %s has being "
45156f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					"hardened on primary and secondary SE\n",
45166f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>					zfcp_get_busid_by_adapter(adapter));
45176f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>				break;
45186f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>
45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE:
45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be saved on the SE\n",
45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2:
45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC of the adapter %s could not "
45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"be copied to the secondary SE\n",
45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_LOG_NORMAL(
45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"CFDC could not be hardened "
45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"on the adapter %s\n",
45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					zfcp_get_busid_by_adapter(adapter));
45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EAGAIN;
45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_AUTHORIZATION_FAILURE:
45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s does not accept privileged commands\n",
45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EACCES;
45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CFDC_ERROR_DETECTED:
45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Error at position %d in the CFDC, "
45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"CFDC is discarded by the adapter %s\n",
45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status_qual.word[0],
45571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPERM;
45601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_UPDATE_ERROR:
45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Adapter %s cannot harden the control file, "
45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"file is discarded\n",
45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONTROL_FILE_TOO_LARGE:
45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Control file is too large, file is discarded "
45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"by the adapter %s\n",
45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_CONFLICT_DETECTED:
45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been discarded by the adapter %s, "
45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"because activation would impact "
45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
45861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_CONFLICTS_OVERRULED:
45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE)
45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ZFCP_LOG_NORMAL(
45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"CFDC has been activated on the adapter %s, "
45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"but activation has impacted "
45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"%d active connection(s)\n",
45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				header->fsf_status_qual.word[0]);
46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, "
46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"op_subtype=0x%x)\n",
46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				zfcp_get_busid_by_adapter(adapter),
46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bottom->operation_subtype);
46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_INVALID_COMMAND_OPTION:
46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Invalid option 0x%x has been specified "
46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"in QTCB bottom sent to the adapter %s\n",
46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bottom->option,
46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
46241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_NORMAL(
46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"bug: An unknown/unexpected FSF status 0x%08x "
46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"was presented on the adapter %s\n",
46271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			header->fsf_status,
46281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_get_busid_by_adapter(adapter));
46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval");
46301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debug_exception(fsf_req->adapter->erp_dbf, 0,
46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&header->fsf_status_qual.word[0], sizeof(u32));
46321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
46331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EINVAL;
46341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
46351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
46421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_check(unsigned long *flags,
46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct zfcp_qdio_queue *queue, int needed)
46441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&queue->queue_lock, *flags);
46461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(atomic_read(&queue->free_count) >= needed))
46471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
46481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock_irqrestore(&queue->queue_lock, *flags);
46491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
46501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set qtcb pointer in fsf_req and initialize QTCB
46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
46554d284cac76d0bfebc42d76b428c4e44d921200a9Heiko Carstensstatic void
46568a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetyninzfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
4659fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.req_seq_no =
4660fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske			fsf_req->adapter->fsf_req_seq_no;
4661fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.req_id = fsf_req->req_id;
46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
4663fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->prefix.qtcb_type =
4664fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske			fsf_qtcb_type[fsf_req->fsf_command];
46651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
4666fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		fsf_req->qtcb->header.req_handle = fsf_req->req_id;
46678a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @adapter: adapter for which request queue is examined
46741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @req_flags: flags indicating whether to wait for needed SBAL or not
46751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @lock_flags: lock_flags if queue_lock is taken
46761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locks: lock adapter->request_queue->queue_lock on success
46781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
46791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
46801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      unsigned long *lock_flags)
46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        long ret;
46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                ret = wait_event_interruptible_timeout(adapter->request_wq,
46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1),
46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       ZFCP_SBAL_TIMEOUT);
46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ret)
46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1))
46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EIO;
46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_create
47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	create an FSF request at the specified adapter and
47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		setup common fields
47051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	-ENOMEM if there was insufficient memory for a request
47071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EIO if no qdio buffers could be allocate to the request
47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              -EINVAL/-EPERM on bug conditions in req_dequeue
47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              0 in success
47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * note:        The created request is returned by reference.
47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locks:	lock of concerned request queue must not be held,
47141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		but is held on completion (write, irqsave)
47151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
47161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
47171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldszfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
47181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    mempool_t *pool, unsigned long *lock_flags,
47191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    struct zfcp_fsf_req **fsf_req_p)
47201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
47221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_fsf_req *fsf_req = NULL;
47231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
47241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
47251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allocate new FSF request */
47271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
47281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(NULL == fsf_req)) {
47291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
47301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "the outbound (send) queue.\n");
47311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
47321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_fsf_req;
47331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47358a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->adapter = adapter;
47368a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->fsf_command = fsf_cmd;
4737fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	INIT_LIST_HEAD(&fsf_req->list);
47382abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann	init_timer(&fsf_req->timer);
47391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
474041fa2adabc0a750a40d6fe86d5ce2f75fb3ad287Swen Schillig	/* initialize waitqueue which may be used to wait on
47411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this request completion */
47421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&fsf_req->completion_wq);
47431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
4745801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt        if (ret < 0)
47461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                goto failed_sbals;
4747801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt
4748801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	/* this is serialized (we are holding req_queue-lock of adapter) */
4749801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	if (adapter->req_no == 0)
4750801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt		adapter->req_no++;
4751801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	fsf_req->req_id = adapter->req_no++;
4752801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt
4753801e0ced1891a2b8cad1a435c45234a719b3b6bfChristof Schmitt	zfcp_fsf_req_qtcb_init(fsf_req);
47541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
47561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We hold queue_lock here. Check if QDIOUP is set and let request fail
47571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if it is not set (see also *_open_qdio and *_close_qdio).
47581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
47591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
47611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags);
47621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EIO;
47631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_sbals;
47641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47668a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (fsf_req->qtcb) {
47678a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->seq_no = adapter->fsf_req_seq_no;
47688a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
47698a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	}
47701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_number = 1;
47711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_first = req_queue->free_index;
47721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req->sbal_curr = req_queue->free_index;
47731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        fsf_req->sbale_curr = 1;
47741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
47761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
47771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
47801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup common SBALE fields */
4782fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	sbale[0].addr = (void *) fsf_req->req_id;
47831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
47841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(fsf_req->qtcb != NULL)) {
47851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].addr = (void *) fsf_req->qtcb;
47861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sbale[1].length = sizeof(struct fsf_qtcb);
47871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n",
47901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                       fsf_req->sbal_number, fsf_req->sbal_first);
47911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto success;
47931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_sbals:
47951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* dequeue new FSF request previously enqueued */
47961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zfcp_fsf_req_free(fsf_req);
47971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fsf_req = NULL;
47981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed_fsf_req:
48001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock_irqsave(&req_queue->queue_lock, *lock_flags);
48011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds success:
48021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fsf_req_p = fsf_req;
48031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
48041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
48051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
48071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function:    zfcp_fsf_req_send
48081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
48091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * purpose:	start transfer of FSF request via QDIO
48101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
48111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns:	0 - request transfer succesfully started
48121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		!0 - start of request transfer failed
48131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
48142abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmannstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
48151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
48161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_adapter *adapter;
48171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_qdio_queue *req_queue;
48181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
48198a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	int inc_seq_no;
48201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int new_distance_from_int;
4821fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	u64 dbg_tmp[2];
48221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
48231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	adapter = fsf_req->adapter;
48251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue = &adapter->request_queue,
48261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME(debug): remove it later */
48291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0);
48301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags);
48311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n");
48321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
48331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      sbale[1].length);
48341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4835fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	/* put allocated FSF request into hash table */
4836fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock(&adapter->req_list_lock);
4837fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	zfcp_reqlist_add(adapter, fsf_req);
4838fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock(&adapter->req_list_lock);
48391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48408a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	inc_seq_no = (fsf_req->qtcb != NULL);
48418a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
48421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("request queue of adapter %s: "
48431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "next free SBAL is %i, %i free SBALs\n",
48441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
48451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       req_queue->free_index,
48461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       atomic_read(&req_queue->free_count));
48471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, "
48491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "index_in_queue=%i, count=%i, buffers=%p\n",
48501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_busid_by_adapter(adapter),
48511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       QDIO_FLAG_SYNC_OUTPUT,
48521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       0, fsf_req->sbal_first, fsf_req->sbal_number,
48531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       &req_queue->buffer[fsf_req->sbal_first]);
48541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
48561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * adjust the number of free SBALs in request queue as well as
48571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * position of first one
48581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
48591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_sub(fsf_req->sbal_number, &req_queue->free_count);
48601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count));
48611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index += fsf_req->sbal_number;	  /* increase */
48621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q;  /* wrap if needed */
48631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
48641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48658a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	fsf_req->issued = get_clock();
48668a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
48671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = do_QDIO(adapter->ccw_device,
48681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 QDIO_FLAG_SYNC_OUTPUT,
48691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
48701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	dbg_tmp[0] = (unsigned long) sbale[0].addr;
4872fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	dbg_tmp[1] = (u64) retval;
4873fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
4874fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
48751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(retval)) {
48761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Queues are down..... */
48771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
48782abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann		del_timer(&fsf_req->timer);
4879fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		spin_lock(&adapter->req_list_lock);
4880ca2d02c2f9ea476062ae181eec60b8bcd97857d6Heiko Carstens		zfcp_reqlist_remove(adapter, fsf_req);
4881fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		spin_unlock(&adapter->req_list_lock);
4882fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		/* undo changes in request queue made for this request */
48831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		zfcp_qdio_zero_sbals(req_queue->buffer,
48841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     fsf_req->sbal_first, fsf_req->sbal_number);
48851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_add(fsf_req->sbal_number, &req_queue->free_count);
4886fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		req_queue->free_index -= fsf_req->sbal_number;
48871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
48881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
4889fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		zfcp_erp_adapter_reopen(adapter, 0);
48901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
48911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req_queue->distance_from_int = new_distance_from_int;
48921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
48931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * increase FSF sequence counter -
48941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this must only be done for request successfully enqueued to
48951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * QDIO this rejected requests may be cleaned up by calling
48961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * routines  resulting in missing sequence counter values
48971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * otherwise,
48981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
48998a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
49001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Don't increase for unsolicited status */
49018a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin		if (inc_seq_no)
49021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adapter->fsf_req_seq_no++;
49038a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
49041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* count FSF requests pending */
4905fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske		atomic_inc(&adapter->reqs_active);
49061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
49071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
49081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
49091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ZFCP_LOG_AREA
4911