| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Andreas Herrmann | 4a9d2d8 | 2006-05-22 18:14:08 +0200 | [diff] [blame] | 2 |  * This file is part of the zfcp device driver for | 
 | 3 |  * FCP adapters for IBM System z9 and zSeries. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 |  * | 
| Andreas Herrmann | 4a9d2d8 | 2006-05-22 18:14:08 +0200 | [diff] [blame] | 5 |  * (C) Copyright IBM Corp. 2002, 2006 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify | 
 | 8 |  * it under the terms of the GNU General Public License as published by | 
 | 9 |  * the Free Software Foundation; either version 2, or (at your option) | 
 | 10 |  * any later version. | 
 | 11 |  * | 
 | 12 |  * This program is distributed in the hope that it will be useful, | 
 | 13 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 15 |  * GNU General Public License for more details. | 
 | 16 |  * | 
 | 17 |  * You should have received a copy of the GNU General Public License | 
 | 18 |  * along with this program; if not, write to the Free Software | 
 | 19 |  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 20 |  */ | 
 | 21 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | #include "zfcp_ext.h" | 
 | 23 |  | 
 | 24 | static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); | 
 | 25 | static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); | 
 | 26 | static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); | 
 | 27 | static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); | 
 | 28 | static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); | 
 | 29 | static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *); | 
 | 30 | static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *); | 
 | 31 | static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *); | 
 | 32 | static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *); | 
 | 33 | static int zfcp_fsf_send_fcp_command_task_management_handler( | 
 | 34 | 	struct zfcp_fsf_req *); | 
 | 35 | static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); | 
 | 36 | static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); | 
 | 37 | static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); | 
 | 38 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); | 
 | 39 | static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); | 
 | 40 | static inline int zfcp_fsf_req_sbal_check( | 
 | 41 | 	unsigned long *, struct zfcp_qdio_queue *, int); | 
 | 42 | static inline int zfcp_use_one_sbal( | 
 | 43 | 	struct scatterlist *, int, struct scatterlist *, int); | 
 | 44 | static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 45 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *); | 
 | 47 | static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); | 
 | 48 | static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 49 | static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *, | 
 | 50 | 	struct fsf_link_down_info *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 |  | 
 | 53 | /* association between FSF command and FSF QTCB type */ | 
 | 54 | static u32 fsf_qtcb_type[] = { | 
 | 55 | 	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND, | 
 | 56 | 	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND, | 
 | 57 | 	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND, | 
 | 58 | 	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND, | 
 | 59 | 	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND, | 
 | 60 | 	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND, | 
 | 61 | 	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND, | 
 | 62 | 	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND, | 
 | 63 | 	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND, | 
 | 64 | 	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND, | 
 | 65 | 	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND, | 
 | 66 | 	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND, | 
 | 67 | 	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND | 
 | 68 | }; | 
 | 69 |  | 
 | 70 | static const char zfcp_act_subtable_type[5][8] = { | 
 | 71 | 	"unknown", "OS", "WWPN", "DID", "LUN" | 
 | 72 | }; | 
 | 73 |  | 
 | 74 | /****************************************************************/ | 
 | 75 | /*************** FSF related Functions  *************************/ | 
 | 76 | /****************************************************************/ | 
 | 77 |  | 
 | 78 | #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF | 
 | 79 |  | 
 | 80 | /* | 
 | 81 |  * function:	zfcp_fsf_req_alloc | 
 | 82 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 83 |  * purpose:     Obtains an fsf_req and potentially a qtcb (for all but | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 |  *              unsolicited requests) via helper functions | 
 | 85 |  *              Does some initial fsf request set-up. | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 86 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 |  * returns:	pointer to allocated fsf_req if successfull | 
 | 88 |  *              NULL otherwise | 
 | 89 |  * | 
 | 90 |  * locks:       none | 
 | 91 |  * | 
 | 92 |  */ | 
 | 93 | static struct zfcp_fsf_req * | 
 | 94 | zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) | 
 | 95 | { | 
 | 96 | 	size_t size; | 
 | 97 | 	void *ptr; | 
 | 98 | 	struct zfcp_fsf_req *fsf_req = NULL; | 
 | 99 |  | 
 | 100 | 	if (req_flags & ZFCP_REQ_NO_QTCB) | 
 | 101 | 		size = sizeof(struct zfcp_fsf_req); | 
 | 102 | 	else | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 103 | 		size = sizeof(struct zfcp_fsf_req_qtcb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 |  | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 105 | 	if (likely(pool)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | 		ptr = mempool_alloc(pool, GFP_ATOMIC); | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 107 | 	else { | 
 | 108 | 		if (req_flags & ZFCP_REQ_NO_QTCB) | 
 | 109 | 			ptr = kmalloc(size, GFP_ATOMIC); | 
 | 110 | 		else | 
 | 111 | 			ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, | 
| Christoph Lameter | 54e6ecb | 2006-12-06 20:33:16 -0800 | [diff] [blame] | 112 | 					       GFP_ATOMIC); | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 113 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 |  | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 115 | 	if (unlikely(!ptr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | 		goto out; | 
 | 117 |  | 
 | 118 | 	memset(ptr, 0, size); | 
 | 119 |  | 
 | 120 | 	if (req_flags & ZFCP_REQ_NO_QTCB) { | 
 | 121 | 		fsf_req = (struct zfcp_fsf_req *) ptr; | 
 | 122 | 	} else { | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 123 | 		fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req; | 
 | 124 | 		fsf_req->qtcb =	&((struct zfcp_fsf_req_qtcb *) ptr)->qtcb; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | 	} | 
 | 126 |  | 
 | 127 | 	fsf_req->pool = pool; | 
 | 128 |  | 
 | 129 |  out: | 
 | 130 | 	return fsf_req; | 
 | 131 | } | 
 | 132 |  | 
 | 133 | /* | 
 | 134 |  * function:	zfcp_fsf_req_free | 
 | 135 |  * | 
 | 136 |  * purpose:     Frees the memory of an fsf_req (and potentially a qtcb) or | 
 | 137 |  *              returns it into the pool via helper functions. | 
 | 138 |  * | 
 | 139 |  * returns:     sod all | 
 | 140 |  * | 
 | 141 |  * locks:       none | 
 | 142 |  */ | 
| Andreas Herrmann | 1db2c9c | 2005-06-13 13:20:35 +0200 | [diff] [blame] | 143 | void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 | zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | 
 | 145 | { | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 146 | 	if (likely(fsf_req->pool)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | 		mempool_free(fsf_req, fsf_req->pool); | 
| Heiko Carstens | dd52e0e | 2006-09-18 22:28:49 +0200 | [diff] [blame] | 148 | 		return; | 
 | 149 | 	} | 
 | 150 |  | 
 | 151 | 	if (fsf_req->qtcb) { | 
 | 152 | 		kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req); | 
 | 153 | 		return; | 
 | 154 | 	} | 
 | 155 |  | 
 | 156 | 	kfree(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 157 | } | 
 | 158 |  | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 159 | /* | 
 | 160 |  * Never ever call this without shutting down the adapter first. | 
 | 161 |  * Otherwise the adapter would continue using and corrupting s390 storage. | 
 | 162 |  * Included BUG_ON() call to ensure this is done. | 
 | 163 |  * ERP is supposed to be the only user of this function. | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 164 |  */ | 
| Swen Schillig | 6fcc471 | 2007-02-07 13:17:57 +0100 | [diff] [blame] | 165 | void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 166 | { | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 167 | 	struct zfcp_fsf_req *fsf_req, *tmp; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 168 | 	unsigned long flags; | 
| Swen Schillig | 6fcc471 | 2007-02-07 13:17:57 +0100 | [diff] [blame] | 169 | 	LIST_HEAD(remove_queue); | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 170 | 	unsigned int i; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 171 |  | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 172 | 	BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)); | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 173 | 	spin_lock_irqsave(&adapter->req_list_lock, flags); | 
 | 174 | 	atomic_set(&adapter->reqs_active, 0); | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 175 | 	for (i = 0; i < REQUEST_LIST_SIZE; i++) | 
| Swen Schillig | 6fcc471 | 2007-02-07 13:17:57 +0100 | [diff] [blame] | 176 | 		list_splice_init(&adapter->req_list[i], &remove_queue); | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 177 | 	spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 
 | 178 |  | 
| Martin Peschke | 869b2b4 | 2007-05-09 11:01:20 +0200 | [diff] [blame] | 179 | 	list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { | 
 | 180 | 		list_del(&fsf_req->list); | 
 | 181 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | 
 | 182 | 		zfcp_fsf_req_complete(fsf_req); | 
| Swen Schillig | 6fcc471 | 2007-02-07 13:17:57 +0100 | [diff] [blame] | 183 | 	} | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 184 | } | 
 | 185 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 | /* | 
 | 187 |  * function:    zfcp_fsf_req_complete | 
 | 188 |  * | 
 | 189 |  * purpose:	Updates active counts and timers for openfcp-reqs | 
 | 190 |  *              May cleanup request after req_eval returns | 
 | 191 |  * | 
 | 192 |  * returns:	0 - success | 
 | 193 |  *		!0 - failure | 
 | 194 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 195 |  * context: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 |  */ | 
 | 197 | int | 
 | 198 | zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) | 
 | 199 | { | 
 | 200 | 	int retval = 0; | 
 | 201 | 	int cleanup; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 |  | 
 | 203 | 	if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { | 
 | 204 | 		ZFCP_LOG_DEBUG("Status read response received\n"); | 
 | 205 | 		/* | 
 | 206 | 		 * Note: all cleanup handling is done in the callchain of | 
 | 207 | 		 * the function call-chain below. | 
 | 208 | 		 */ | 
 | 209 | 		zfcp_fsf_status_read_handler(fsf_req); | 
 | 210 | 		goto out; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 211 | 	} else { | 
 | 212 | 		del_timer(&fsf_req->timer); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 213 | 		zfcp_fsf_protstatus_eval(fsf_req); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 214 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 |  | 
 | 216 | 	/* | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 217 | 	 * fsf_req may be deleted due to waking up functions, so | 
 | 218 | 	 * cleanup is saved here and used later | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 219 | 	 */ | 
 | 220 | 	if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) | 
 | 221 | 		cleanup = 1; | 
 | 222 | 	else | 
 | 223 | 		cleanup = 0; | 
 | 224 |  | 
 | 225 | 	fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; | 
 | 226 |  | 
 | 227 | 	/* cleanup request if requested by initiator */ | 
 | 228 | 	if (likely(cleanup)) { | 
 | 229 | 		ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req); | 
 | 230 | 		/* | 
 | 231 | 		 * lock must not be held here since it will be | 
 | 232 | 		 * grabed by the called routine, too | 
 | 233 | 		 */ | 
| Andreas Herrmann | 1db2c9c | 2005-06-13 13:20:35 +0200 | [diff] [blame] | 234 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | 	} else { | 
 | 236 | 		/* notify initiator waiting for the requests completion */ | 
 | 237 | 		ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); | 
 | 238 | 		/* | 
 | 239 | 		 * FIXME: Race! We must not access fsf_req here as it might have been | 
 | 240 | 		 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED | 
 | 241 | 		 * flag. It's an improbable case. But, we have the same paranoia for | 
 | 242 | 		 * the cleanup flag already. | 
 | 243 | 		 * Might better be handled using complete()? | 
 | 244 | 		 * (setting the flag and doing wakeup ought to be atomic | 
 | 245 | 		 *  with regard to checking the flag as long as waitqueue is | 
 | 246 | 		 *  part of the to be released structure) | 
 | 247 | 		 */ | 
 | 248 | 		wake_up(&fsf_req->completion_wq); | 
 | 249 | 	} | 
 | 250 |  | 
 | 251 |  out: | 
 | 252 | 	return retval; | 
 | 253 | } | 
 | 254 |  | 
 | 255 | /* | 
 | 256 |  * function:    zfcp_fsf_protstatus_eval | 
 | 257 |  * | 
 | 258 |  * purpose:	evaluates the QTCB of the finished FSF request | 
 | 259 |  *		and initiates appropriate actions | 
 | 260 |  *		(usually calling FSF command specific handlers) | 
 | 261 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 262 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 263 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 264 |  * context: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 265 |  * | 
 | 266 |  * locks: | 
 | 267 |  */ | 
 | 268 | static int | 
 | 269 | zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) | 
 | 270 | { | 
 | 271 | 	int retval = 0; | 
 | 272 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 273 | 	struct fsf_qtcb *qtcb = fsf_req->qtcb; | 
 | 274 | 	union fsf_prot_status_qual *prot_status_qual = | 
 | 275 | 		&qtcb->prefix.prot_status_qual; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 277 | 	zfcp_hba_dbf_event_fsf_response(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 278 |  | 
 | 279 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | 
 | 280 | 		ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n", | 
 | 281 | 			       (unsigned long) fsf_req); | 
 | 282 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | 
 | 283 | 			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 284 | 		goto skip_protstatus; | 
 | 285 | 	} | 
 | 286 |  | 
 | 287 | 	/* log additional information provided by FSF (if any) */ | 
| Heiko Carstens | 862794f | 2007-02-21 09:28:00 +0100 | [diff] [blame] | 288 | 	if (likely(qtcb->header.log_length)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | 		/* do not trust them ;-) */ | 
| Heiko Carstens | 862794f | 2007-02-21 09:28:00 +0100 | [diff] [blame] | 290 | 		if (unlikely(qtcb->header.log_start > | 
 | 291 | 			     sizeof(struct fsf_qtcb))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 292 | 			ZFCP_LOG_NORMAL | 
 | 293 | 			    ("bug: ULP (FSF logging) log data starts " | 
 | 294 | 			     "beyond end of packet header. Ignored. " | 
 | 295 | 			     "(start=%i, size=%li)\n", | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 296 | 			     qtcb->header.log_start, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 | 			     sizeof(struct fsf_qtcb)); | 
 | 298 | 			goto forget_log; | 
 | 299 | 		} | 
| Heiko Carstens | 862794f | 2007-02-21 09:28:00 +0100 | [diff] [blame] | 300 | 		if (unlikely((size_t) (qtcb->header.log_start + | 
 | 301 | 				       qtcb->header.log_length) > | 
 | 302 | 			     sizeof(struct fsf_qtcb))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | 			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends " | 
 | 304 | 					"beyond end of packet header. Ignored. " | 
 | 305 | 					"(start=%i, length=%i, size=%li)\n", | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 306 | 					qtcb->header.log_start, | 
 | 307 | 					qtcb->header.log_length, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | 					sizeof(struct fsf_qtcb)); | 
 | 309 | 			goto forget_log; | 
 | 310 | 		} | 
 | 311 | 		ZFCP_LOG_TRACE("ULP log data: \n"); | 
 | 312 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 313 | 			      (char *) qtcb + qtcb->header.log_start, | 
 | 314 | 			      qtcb->header.log_length); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 315 | 	} | 
 | 316 |  forget_log: | 
 | 317 |  | 
 | 318 | 	/* evaluate FSF Protocol Status */ | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 319 | 	switch (qtcb->prefix.prot_status) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 |  | 
 | 321 | 	case FSF_PROT_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 322 | 	case FSF_PROT_FSF_STATUS_PRESENTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 323 | 		break; | 
 | 324 |  | 
 | 325 | 	case FSF_PROT_QTCB_VERSION_ERROR: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 326 | 		ZFCP_LOG_NORMAL("error: The adapter %s contains " | 
 | 327 | 				"microcode of version 0x%x, the device driver " | 
 | 328 | 				"only supports 0x%x. Aborting.\n", | 
 | 329 | 				zfcp_get_busid_by_adapter(adapter), | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 330 | 				prot_status_qual->version_error.fsf_version, | 
 | 331 | 				ZFCP_QTCB_VERSION); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 332 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 333 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 334 | 		break; | 
 | 335 |  | 
 | 336 | 	case FSF_PROT_SEQ_NUMB_ERROR: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | 		ZFCP_LOG_NORMAL("bug: Sequence number mismatch between " | 
 | 338 | 				"driver (0x%x) and adapter %s (0x%x). " | 
 | 339 | 				"Restarting all operations on this adapter.\n", | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 340 | 				qtcb->prefix.req_seq_no, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 341 | 				zfcp_get_busid_by_adapter(adapter), | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 342 | 				prot_status_qual->sequence_error.exp_req_seq_no); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 343 | 		zfcp_erp_adapter_reopen(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 344 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | 
 | 345 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 346 | 		break; | 
 | 347 |  | 
 | 348 | 	case FSF_PROT_UNSUPP_QTCB_TYPE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | 		ZFCP_LOG_NORMAL("error: Packet header type used by the " | 
 | 350 | 				"device driver is incompatible with " | 
 | 351 | 				"that used on adapter %s. " | 
 | 352 | 				"Stopping all operations on this adapter.\n", | 
 | 353 | 				zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 354 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 356 | 		break; | 
 | 357 |  | 
 | 358 | 	case FSF_PROT_HOST_CONNECTION_INITIALIZING: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 360 | 		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | 
 | 361 | 				&(adapter->status)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 362 | 		break; | 
 | 363 |  | 
 | 364 | 	case FSF_PROT_DUPLICATE_REQUEST_ID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 | 			ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx " | 
 | 366 | 					"to the adapter %s is ambiguous. " | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 367 | 				"Stopping all operations on this adapter.\n", | 
 | 368 | 				*(unsigned long long*) | 
 | 369 | 				(&qtcb->bottom.support.req_handle), | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 | 					zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 371 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 372 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 373 | 		break; | 
 | 374 |  | 
 | 375 | 	case FSF_PROT_LINK_DOWN: | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 376 | 		zfcp_fsf_link_down_info_eval(adapter, | 
 | 377 | 					     &prot_status_qual->link_down_info); | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 378 | 		zfcp_erp_adapter_reopen(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 379 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 380 | 		break; | 
 | 381 |  | 
 | 382 | 	case FSF_PROT_REEST_QUEUE: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 383 | 		ZFCP_LOG_NORMAL("The local link to adapter with " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 | 			      "%s was re-plugged. " | 
 | 385 | 			      "Re-starting operations on this adapter.\n", | 
 | 386 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 387 | 		/* All ports should be marked as ready to run again */ | 
 | 388 | 		zfcp_erp_modify_adapter_status(adapter, | 
 | 389 | 					       ZFCP_STATUS_COMMON_RUNNING, | 
 | 390 | 					       ZFCP_SET); | 
 | 391 | 		zfcp_erp_adapter_reopen(adapter, | 
 | 392 | 					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | 
 | 393 | 					| ZFCP_STATUS_COMMON_ERP_FAILED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 394 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 395 | 		break; | 
 | 396 |  | 
 | 397 | 	case FSF_PROT_ERROR_STATE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 398 | 		ZFCP_LOG_NORMAL("error: The adapter %s " | 
 | 399 | 				"has entered the error state. " | 
 | 400 | 				"Restarting all operations on this " | 
 | 401 | 				"adapter.\n", | 
 | 402 | 				zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 403 | 		zfcp_erp_adapter_reopen(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 404 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | 
 | 405 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 406 | 		break; | 
 | 407 |  | 
 | 408 | 	default: | 
 | 409 | 		ZFCP_LOG_NORMAL("bug: Transfer protocol status information " | 
 | 410 | 				"provided by the adapter %s " | 
 | 411 | 				"is not compatible with the device driver. " | 
 | 412 | 				"Stopping all operations on this adapter. " | 
 | 413 | 				"(debug info 0x%x).\n", | 
 | 414 | 				zfcp_get_busid_by_adapter(adapter), | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 415 | 				qtcb->prefix.prot_status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 416 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 417 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 418 | 	} | 
 | 419 |  | 
 | 420 |  skip_protstatus: | 
 | 421 | 	/* | 
 | 422 | 	 * always call specific handlers to give them a chance to do | 
 | 423 | 	 * something meaningful even in error cases | 
 | 424 | 	 */ | 
 | 425 | 	zfcp_fsf_fsfstatus_eval(fsf_req); | 
 | 426 | 	return retval; | 
 | 427 | } | 
 | 428 |  | 
 | 429 | /* | 
 | 430 |  * function:	zfcp_fsf_fsfstatus_eval | 
 | 431 |  * | 
 | 432 |  * purpose:	evaluates FSF status of completed FSF request | 
 | 433 |  *		and acts accordingly | 
 | 434 |  * | 
 | 435 |  * returns: | 
 | 436 |  */ | 
 | 437 | static int | 
 | 438 | zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) | 
 | 439 | { | 
 | 440 | 	int retval = 0; | 
 | 441 |  | 
 | 442 | 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 
 | 443 | 		goto skip_fsfstatus; | 
 | 444 | 	} | 
 | 445 |  | 
 | 446 | 	/* evaluate FSF Status */ | 
 | 447 | 	switch (fsf_req->qtcb->header.fsf_status) { | 
 | 448 | 	case FSF_UNKNOWN_COMMAND: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 449 | 		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | 
 | 450 | 				"not known by the adapter %s " | 
 | 451 | 				"Stopping all operations on this adapter. " | 
 | 452 | 				"(debug info 0x%x).\n", | 
 | 453 | 				zfcp_get_busid_by_adapter(fsf_req->adapter), | 
 | 454 | 				fsf_req->qtcb->header.fsf_command); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 455 | 		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 456 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 457 | 		break; | 
 | 458 |  | 
 | 459 | 	case FSF_FCP_RSP_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 460 | 		ZFCP_LOG_DEBUG("FCP Sense data will be presented to the " | 
 | 461 | 			       "SCSI stack.\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 462 | 		break; | 
 | 463 |  | 
 | 464 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 465 | 		zfcp_fsf_fsfstatus_qual_eval(fsf_req); | 
 | 466 | 		break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 467 | 	} | 
 | 468 |  | 
 | 469 |  skip_fsfstatus: | 
 | 470 | 	/* | 
 | 471 | 	 * always call specific handlers to give them a chance to do | 
 | 472 | 	 * something meaningful even in error cases | 
 | 473 | 	 */ | 
 | 474 | 	zfcp_fsf_req_dispatch(fsf_req); | 
 | 475 |  | 
 | 476 | 	return retval; | 
 | 477 | } | 
 | 478 |  | 
 | 479 | /* | 
 | 480 |  * function:	zfcp_fsf_fsfstatus_qual_eval | 
 | 481 |  * | 
 | 482 |  * purpose:	evaluates FSF status-qualifier of completed FSF request | 
 | 483 |  *		and acts accordingly | 
 | 484 |  * | 
 | 485 |  * returns: | 
 | 486 |  */ | 
 | 487 | static int | 
 | 488 | zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) | 
 | 489 | { | 
 | 490 | 	int retval = 0; | 
 | 491 |  | 
 | 492 | 	switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 
 | 493 | 	case FSF_SQ_FCP_RSP_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 494 | 		break; | 
 | 495 | 	case FSF_SQ_RETRY_IF_POSSIBLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 | 		/* The SCSI-stack may now issue retries or escalate */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 497 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 498 | 		break; | 
 | 499 | 	case FSF_SQ_COMMAND_ABORTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 500 | 		/* Carry the aborted state on to upper layer */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 501 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED; | 
 | 502 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 503 | 		break; | 
 | 504 | 	case FSF_SQ_NO_RECOM: | 
| Joe Perches | ceb3dfb | 2008-01-26 14:11:10 +0100 | [diff] [blame] | 505 | 		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 506 | 				"problem on the adapter %s " | 
 | 507 | 				"Stopping all operations on this adapter. ", | 
 | 508 | 				zfcp_get_busid_by_adapter(fsf_req->adapter)); | 
 | 509 | 		zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 511 | 		break; | 
 | 512 | 	case FSF_SQ_ULP_PROGRAMMING_ERROR: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 | 		ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " | 
 | 514 | 				"(adapter %s)\n", | 
 | 515 | 				zfcp_get_busid_by_adapter(fsf_req->adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 516 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 517 | 		break; | 
 | 518 | 	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
 | 519 | 	case FSF_SQ_NO_RETRY_POSSIBLE: | 
 | 520 | 	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
 | 521 | 		/* dealt with in the respective functions */ | 
 | 522 | 		break; | 
 | 523 | 	default: | 
 | 524 | 		ZFCP_LOG_NORMAL("bug: Additional status info could " | 
 | 525 | 				"not be interpreted properly.\n"); | 
 | 526 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 
 | 527 | 			      (char *) &fsf_req->qtcb->header.fsf_status_qual, | 
 | 528 | 			      sizeof (union fsf_status_qual)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 530 | 		break; | 
 | 531 | 	} | 
 | 532 |  | 
 | 533 | 	return retval; | 
 | 534 | } | 
 | 535 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 536 | /** | 
 | 537 |  * zfcp_fsf_link_down_info_eval - evaluate link down information block | 
 | 538 |  */ | 
 | 539 | static void | 
 | 540 | zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, | 
 | 541 | 			     struct fsf_link_down_info *link_down) | 
 | 542 | { | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 543 | 	if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, | 
 | 544 | 	                     &adapter->status)) | 
 | 545 | 		return; | 
 | 546 |  | 
 | 547 | 	atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); | 
 | 548 |  | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 549 | 	if (link_down == NULL) | 
 | 550 | 		goto out; | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 551 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 552 | 	switch (link_down->error_code) { | 
 | 553 | 	case FSF_PSQ_LINK_NO_LIGHT: | 
 | 554 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 555 | 				"(no light detected)\n", | 
 | 556 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 557 | 		break; | 
 | 558 | 	case FSF_PSQ_LINK_WRAP_PLUG: | 
 | 559 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 560 | 				"(wrap plug detected)\n", | 
 | 561 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 562 | 		break; | 
 | 563 | 	case FSF_PSQ_LINK_NO_FCP: | 
 | 564 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 565 | 				"(adjacent node on link does not support FCP)\n", | 
 | 566 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 567 | 		break; | 
 | 568 | 	case FSF_PSQ_LINK_FIRMWARE_UPDATE: | 
 | 569 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 570 | 				"(firmware update in progress)\n", | 
 | 571 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 572 | 			break; | 
 | 573 | 	case FSF_PSQ_LINK_INVALID_WWPN: | 
 | 574 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 575 | 				"(duplicate or invalid WWPN detected)\n", | 
 | 576 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 577 | 		break; | 
 | 578 | 	case FSF_PSQ_LINK_NO_NPIV_SUPPORT: | 
 | 579 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 580 | 				"(no support for NPIV by Fabric)\n", | 
 | 581 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 582 | 		break; | 
 | 583 | 	case FSF_PSQ_LINK_NO_FCP_RESOURCES: | 
 | 584 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 585 | 				"(out of resource in FCP daughtercard)\n", | 
 | 586 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 587 | 		break; | 
 | 588 | 	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: | 
 | 589 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 590 | 				"(out of resource in Fabric)\n", | 
 | 591 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 592 | 		break; | 
 | 593 | 	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: | 
 | 594 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 595 | 				"(unable to Fabric login)\n", | 
 | 596 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 597 | 		break; | 
 | 598 | 	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: | 
 | 599 | 		ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n", | 
 | 600 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 601 | 		break; | 
 | 602 | 	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: | 
 | 603 | 		ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n", | 
 | 604 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 605 | 		break; | 
 | 606 | 	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: | 
 | 607 | 		ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n", | 
 | 608 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 609 | 		break; | 
 | 610 | 	default: | 
 | 611 | 		ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 
 | 612 | 				"(warning: unknown reason code %d)\n", | 
 | 613 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 614 | 				link_down->error_code); | 
 | 615 | 	} | 
 | 616 |  | 
 | 617 | 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | 
 | 618 | 		ZFCP_LOG_DEBUG("Debug information to link down: " | 
 | 619 | 		               "primary_status=0x%02x " | 
 | 620 | 		               "ioerr_code=0x%02x " | 
 | 621 | 		               "action_code=0x%02x " | 
 | 622 | 		               "reason_code=0x%02x " | 
 | 623 | 		               "explanation_code=0x%02x " | 
 | 624 | 		               "vendor_specific_code=0x%02x\n", | 
 | 625 | 				link_down->primary_status, | 
 | 626 | 				link_down->ioerr_code, | 
 | 627 | 				link_down->action_code, | 
 | 628 | 				link_down->reason_code, | 
 | 629 | 				link_down->explanation_code, | 
 | 630 | 				link_down->vendor_specific_code); | 
 | 631 |  | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 632 |  out: | 
 | 633 | 	zfcp_erp_adapter_failed(adapter); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 634 | } | 
 | 635 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 636 | /* | 
 | 637 |  * function:	zfcp_fsf_req_dispatch | 
 | 638 |  * | 
 | 639 |  * purpose:	calls the appropriate command specific handler | 
 | 640 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 641 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 642 |  */ | 
 | 643 | static int | 
 | 644 | zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) | 
 | 645 | { | 
 | 646 | 	struct zfcp_erp_action *erp_action = fsf_req->erp_action; | 
 | 647 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
 | 648 | 	int retval = 0; | 
 | 649 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 650 |  | 
 | 651 | 	switch (fsf_req->fsf_command) { | 
 | 652 |  | 
 | 653 | 	case FSF_QTCB_FCP_CMND: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 654 | 		zfcp_fsf_send_fcp_command_handler(fsf_req); | 
 | 655 | 		break; | 
 | 656 |  | 
 | 657 | 	case FSF_QTCB_ABORT_FCP_CMND: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 | 		zfcp_fsf_abort_fcp_command_handler(fsf_req); | 
 | 659 | 		break; | 
 | 660 |  | 
 | 661 | 	case FSF_QTCB_SEND_GENERIC: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 662 | 		zfcp_fsf_send_ct_handler(fsf_req); | 
 | 663 | 		break; | 
 | 664 |  | 
 | 665 | 	case FSF_QTCB_OPEN_PORT_WITH_DID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 666 | 		zfcp_fsf_open_port_handler(fsf_req); | 
 | 667 | 		break; | 
 | 668 |  | 
 | 669 | 	case FSF_QTCB_OPEN_LUN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 670 | 		zfcp_fsf_open_unit_handler(fsf_req); | 
 | 671 | 		break; | 
 | 672 |  | 
 | 673 | 	case FSF_QTCB_CLOSE_LUN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 674 | 		zfcp_fsf_close_unit_handler(fsf_req); | 
 | 675 | 		break; | 
 | 676 |  | 
 | 677 | 	case FSF_QTCB_CLOSE_PORT: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 678 | 		zfcp_fsf_close_port_handler(fsf_req); | 
 | 679 | 		break; | 
 | 680 |  | 
 | 681 | 	case FSF_QTCB_CLOSE_PHYSICAL_PORT: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 682 | 		zfcp_fsf_close_physical_port_handler(fsf_req); | 
 | 683 | 		break; | 
 | 684 |  | 
 | 685 | 	case FSF_QTCB_EXCHANGE_CONFIG_DATA: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 686 | 		zfcp_fsf_exchange_config_data_handler(fsf_req); | 
 | 687 | 		break; | 
 | 688 |  | 
 | 689 | 	case FSF_QTCB_EXCHANGE_PORT_DATA: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 690 | 		zfcp_fsf_exchange_port_data_handler(fsf_req); | 
 | 691 | 		break; | 
 | 692 |  | 
 | 693 | 	case FSF_QTCB_SEND_ELS: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 694 | 		zfcp_fsf_send_els_handler(fsf_req); | 
 | 695 | 		break; | 
 | 696 |  | 
 | 697 | 	case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 698 | 		zfcp_fsf_control_file_handler(fsf_req); | 
 | 699 | 		break; | 
 | 700 |  | 
 | 701 | 	case FSF_QTCB_UPLOAD_CONTROL_FILE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 702 | 		zfcp_fsf_control_file_handler(fsf_req); | 
 | 703 | 		break; | 
 | 704 |  | 
 | 705 | 	default: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 706 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 707 | 		ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | 
 | 708 | 				"not supported by the adapter %s\n", | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 709 | 				zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 710 | 		if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command) | 
 | 711 | 			ZFCP_LOG_NORMAL | 
 | 712 | 			    ("bug: Command issued by the device driver differs " | 
 | 713 | 			     "from the command returned by the adapter %s " | 
 | 714 | 			     "(debug info 0x%x, 0x%x).\n", | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 715 | 			     zfcp_get_busid_by_adapter(adapter), | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 716 | 			     fsf_req->fsf_command, | 
 | 717 | 			     fsf_req->qtcb->header.fsf_command); | 
 | 718 | 	} | 
 | 719 |  | 
 | 720 | 	if (!erp_action) | 
 | 721 | 		return retval; | 
 | 722 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 723 | 	zfcp_erp_async_handler(erp_action, 0); | 
 | 724 |  | 
 | 725 | 	return retval; | 
 | 726 | } | 
 | 727 |  | 
 | 728 | /* | 
 | 729 |  * function:    zfcp_fsf_status_read | 
 | 730 |  * | 
 | 731 |  * purpose:	initiates a Status Read command at the specified adapter | 
 | 732 |  * | 
 | 733 |  * returns: | 
 | 734 |  */ | 
 | 735 | int | 
 | 736 | zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) | 
 | 737 | { | 
 | 738 | 	struct zfcp_fsf_req *fsf_req; | 
 | 739 | 	struct fsf_status_read_buffer *status_buffer; | 
 | 740 | 	unsigned long lock_flags; | 
 | 741 | 	volatile struct qdio_buffer_element *sbale; | 
 | 742 | 	int retval = 0; | 
 | 743 |  | 
 | 744 | 	/* setup new FSF request */ | 
 | 745 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, | 
 | 746 | 				     req_flags | ZFCP_REQ_NO_QTCB, | 
 | 747 | 				     adapter->pool.fsf_req_status_read, | 
 | 748 | 				     &lock_flags, &fsf_req); | 
 | 749 | 	if (retval < 0) { | 
 | 750 | 		ZFCP_LOG_INFO("error: Could not create unsolicited status " | 
 | 751 | 			      "buffer for adapter %s.\n", | 
 | 752 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 753 | 		goto failed_req_create; | 
 | 754 | 	} | 
 | 755 |  | 
 | 756 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 757 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; | 
 | 758 |         sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 759 |         fsf_req->sbale_curr = 2; | 
 | 760 |  | 
 | 761 | 	status_buffer = | 
 | 762 | 		mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); | 
 | 763 | 	if (!status_buffer) { | 
 | 764 | 		ZFCP_LOG_NORMAL("bug: could not get some buffer\n"); | 
 | 765 | 		goto failed_buf; | 
 | 766 | 	} | 
 | 767 | 	memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 768 | 	fsf_req->data = (unsigned long) status_buffer; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 769 |  | 
 | 770 | 	/* insert pointer to respective buffer */ | 
 | 771 | 	sbale = zfcp_qdio_sbale_curr(fsf_req); | 
 | 772 | 	sbale->addr = (void *) status_buffer; | 
 | 773 | 	sbale->length = sizeof(struct fsf_status_read_buffer); | 
 | 774 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 775 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 776 | 	if (retval) { | 
 | 777 | 		ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status " | 
 | 778 | 			       "environment.\n"); | 
 | 779 | 		goto failed_req_send; | 
 | 780 | 	} | 
 | 781 |  | 
 | 782 | 	ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", | 
 | 783 | 		       zfcp_get_busid_by_adapter(adapter)); | 
 | 784 | 	goto out; | 
 | 785 |  | 
 | 786 |  failed_req_send: | 
 | 787 | 	mempool_free(status_buffer, adapter->pool.data_status_read); | 
 | 788 |  | 
 | 789 |  failed_buf: | 
 | 790 | 	zfcp_fsf_req_free(fsf_req); | 
 | 791 |  failed_req_create: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 792 | 	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 793 |  out: | 
 | 794 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 795 | 	return retval; | 
 | 796 | } | 
 | 797 |  | 
 | 798 | static int | 
 | 799 | zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) | 
 | 800 | { | 
 | 801 | 	struct fsf_status_read_buffer *status_buffer; | 
 | 802 | 	struct zfcp_adapter *adapter; | 
 | 803 | 	struct zfcp_port *port; | 
 | 804 | 	unsigned long flags; | 
 | 805 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 806 | 	status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 807 | 	adapter = fsf_req->adapter; | 
 | 808 |  | 
 | 809 | 	read_lock_irqsave(&zfcp_data.config_lock, flags); | 
 | 810 | 	list_for_each_entry(port, &adapter->port_list_head, list) | 
 | 811 | 	    if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK)) | 
 | 812 | 		break; | 
 | 813 | 	read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 
 | 814 |  | 
 | 815 | 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { | 
| Joe Perches | ceb3dfb | 2008-01-26 14:11:10 +0100 | [diff] [blame] | 816 | 		ZFCP_LOG_NORMAL("bug: Reopen port indication received for " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 817 | 				"nonexisting port with d_id 0x%06x on " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 818 | 				"adapter %s. Ignored.\n", | 
 | 819 | 				status_buffer->d_id & ZFCP_DID_MASK, | 
 | 820 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 821 | 		goto out; | 
 | 822 | 	} | 
 | 823 |  | 
 | 824 | 	switch (status_buffer->status_subtype) { | 
 | 825 |  | 
 | 826 | 	case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 827 | 		debug_text_event(adapter->erp_dbf, 3, "unsol_pc_phys:"); | 
 | 828 | 		zfcp_erp_port_reopen(port, 0); | 
 | 829 | 		break; | 
 | 830 |  | 
 | 831 | 	case FSF_STATUS_READ_SUB_ERROR_PORT: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 832 | 		debug_text_event(adapter->erp_dbf, 1, "unsol_pc_err:"); | 
 | 833 | 		zfcp_erp_port_shutdown(port, 0); | 
 | 834 | 		break; | 
 | 835 |  | 
 | 836 | 	default: | 
 | 837 | 		debug_text_event(adapter->erp_dbf, 0, "unsol_unk_sub:"); | 
 | 838 | 		debug_exception(adapter->erp_dbf, 0, | 
 | 839 | 				&status_buffer->status_subtype, sizeof (u32)); | 
 | 840 | 		ZFCP_LOG_NORMAL("bug: Undefined status subtype received " | 
 | 841 | 				"for a reopen indication on port with " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 842 | 				"d_id 0x%06x on the adapter %s. " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 843 | 				"Ignored. (debug info 0x%x)\n", | 
 | 844 | 				status_buffer->d_id, | 
 | 845 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 846 | 				status_buffer->status_subtype); | 
 | 847 | 	} | 
 | 848 |  out: | 
 | 849 | 	return 0; | 
 | 850 | } | 
 | 851 |  | 
 | 852 | /* | 
 | 853 |  * function:    zfcp_fsf_status_read_handler | 
 | 854 |  * | 
 | 855 |  * purpose:	is called for finished Open Port command | 
 | 856 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 857 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 858 |  */ | 
 | 859 | static int | 
 | 860 | zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | 
 | 861 | { | 
 | 862 | 	int retval = 0; | 
 | 863 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
 | 864 | 	struct fsf_status_read_buffer *status_buffer = | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 865 | 		(struct fsf_status_read_buffer *) fsf_req->data; | 
| Ralph Wuerthner | b7a52fa | 2006-05-22 18:21:28 +0200 | [diff] [blame] | 866 | 	struct fsf_bit_error_payload *fsf_bit_error; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 867 |  | 
 | 868 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 869 | 		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 870 | 		mempool_free(status_buffer, adapter->pool.data_status_read); | 
| Andreas Herrmann | 1db2c9c | 2005-06-13 13:20:35 +0200 | [diff] [blame] | 871 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 872 | 		goto out; | 
 | 873 | 	} | 
 | 874 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 875 | 	zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer); | 
 | 876 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 877 | 	switch (status_buffer->status_type) { | 
 | 878 |  | 
 | 879 | 	case FSF_STATUS_READ_PORT_CLOSED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 880 | 		zfcp_fsf_status_read_port_closed(fsf_req); | 
 | 881 | 		break; | 
 | 882 |  | 
 | 883 | 	case FSF_STATUS_READ_INCOMING_ELS: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 884 | 		zfcp_fsf_incoming_els(fsf_req); | 
 | 885 | 		break; | 
 | 886 |  | 
 | 887 | 	case FSF_STATUS_READ_SENSE_DATA_AVAIL: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 888 | 		ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", | 
 | 889 | 			      zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 890 | 		break; | 
 | 891 |  | 
 | 892 | 	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: | 
| Ralph Wuerthner | b7a52fa | 2006-05-22 18:21:28 +0200 | [diff] [blame] | 893 | 		fsf_bit_error = (struct fsf_bit_error_payload *) | 
 | 894 | 			status_buffer->payload; | 
 | 895 | 		ZFCP_LOG_NORMAL("Warning: bit error threshold data " | 
 | 896 | 		    "received (adapter %s, " | 
 | 897 | 		    "link failures = %i, loss of sync errors = %i, " | 
 | 898 | 		    "loss of signal errors = %i, " | 
 | 899 | 		    "primitive sequence errors = %i, " | 
 | 900 | 		    "invalid transmission word errors = %i, " | 
 | 901 | 		    "CRC errors = %i)\n", | 
 | 902 | 		    zfcp_get_busid_by_adapter(adapter), | 
 | 903 | 		    fsf_bit_error->link_failure_error_count, | 
 | 904 | 		    fsf_bit_error->loss_of_sync_error_count, | 
 | 905 | 		    fsf_bit_error->loss_of_signal_error_count, | 
 | 906 | 		    fsf_bit_error->primitive_sequence_error_count, | 
 | 907 | 		    fsf_bit_error->invalid_transmission_word_error_count, | 
 | 908 | 		    fsf_bit_error->crc_error_count); | 
 | 909 | 		ZFCP_LOG_INFO("Additional bit error threshold data " | 
 | 910 | 		    "(adapter %s, " | 
 | 911 | 		    "primitive sequence event time-outs = %i, " | 
 | 912 | 		    "elastic buffer overrun errors = %i, " | 
 | 913 | 		    "advertised receive buffer-to-buffer credit = %i, " | 
 | 914 | 		    "current receice buffer-to-buffer credit = %i, " | 
 | 915 | 		    "advertised transmit buffer-to-buffer credit = %i, " | 
 | 916 | 		    "current transmit buffer-to-buffer credit = %i)\n", | 
 | 917 | 		    zfcp_get_busid_by_adapter(adapter), | 
 | 918 | 		    fsf_bit_error->primitive_sequence_event_timeout_count, | 
 | 919 | 		    fsf_bit_error->elastic_buffer_overrun_error_count, | 
 | 920 | 		    fsf_bit_error->advertised_receive_b2b_credit, | 
 | 921 | 		    fsf_bit_error->current_receive_b2b_credit, | 
 | 922 | 		    fsf_bit_error->advertised_transmit_b2b_credit, | 
 | 923 | 		    fsf_bit_error->current_transmit_b2b_credit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 924 | 		break; | 
 | 925 |  | 
 | 926 | 	case FSF_STATUS_READ_LINK_DOWN: | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 927 | 		switch (status_buffer->status_subtype) { | 
 | 928 | 		case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: | 
 | 929 | 			ZFCP_LOG_INFO("Physical link to adapter %s is down\n", | 
 | 930 | 				      zfcp_get_busid_by_adapter(adapter)); | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 931 | 			zfcp_fsf_link_down_info_eval(adapter, | 
 | 932 | 				(struct fsf_link_down_info *) | 
 | 933 | 				&status_buffer->payload); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 934 | 			break; | 
 | 935 | 		case FSF_STATUS_READ_SUB_FDISC_FAILED: | 
 | 936 | 			ZFCP_LOG_INFO("Local link to adapter %s is down " | 
 | 937 | 				      "due to failed FDISC login\n", | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 938 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 939 | 			zfcp_fsf_link_down_info_eval(adapter, | 
 | 940 | 				(struct fsf_link_down_info *) | 
 | 941 | 				&status_buffer->payload); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 942 | 			break; | 
 | 943 | 		case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: | 
 | 944 | 			ZFCP_LOG_INFO("Local link to adapter %s is down " | 
 | 945 | 				      "due to firmware update on adapter\n", | 
 | 946 | 				      zfcp_get_busid_by_adapter(adapter)); | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 947 | 			zfcp_fsf_link_down_info_eval(adapter, NULL); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 948 | 			break; | 
 | 949 | 		default: | 
 | 950 | 			ZFCP_LOG_INFO("Local link to adapter %s is down " | 
 | 951 | 				      "due to unknown reason\n", | 
 | 952 | 				      zfcp_get_busid_by_adapter(adapter)); | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 953 | 			zfcp_fsf_link_down_info_eval(adapter, NULL); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 954 | 		}; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 955 | 		break; | 
 | 956 |  | 
 | 957 | 	case FSF_STATUS_READ_LINK_UP: | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 958 | 		ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " | 
| Maxim Shchetynin | ee69ab7 | 2005-12-01 02:48:41 +0100 | [diff] [blame] | 959 | 				"Restarting operations on this adapter\n", | 
 | 960 | 				zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 961 | 		/* All ports should be marked as ready to run again */ | 
 | 962 | 		zfcp_erp_modify_adapter_status(adapter, | 
 | 963 | 					       ZFCP_STATUS_COMMON_RUNNING, | 
 | 964 | 					       ZFCP_SET); | 
 | 965 | 		zfcp_erp_adapter_reopen(adapter, | 
 | 966 | 					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | 
 | 967 | 					| ZFCP_STATUS_COMMON_ERP_FAILED); | 
 | 968 | 		break; | 
 | 969 |  | 
| Maxim Shchetynin | 9eb69af | 2006-01-05 09:56:47 +0100 | [diff] [blame] | 970 | 	case FSF_STATUS_READ_NOTIFICATION_LOST: | 
 | 971 | 		ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: " | 
 | 972 | 				"adapter %s%s%s%s%s%s%s%s%s\n", | 
 | 973 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 974 | 				(status_buffer->status_subtype & | 
 | 975 | 					FSF_STATUS_READ_SUB_INCOMING_ELS) ? | 
 | 976 | 					", incoming ELS" : "", | 
 | 977 | 				(status_buffer->status_subtype & | 
 | 978 | 					FSF_STATUS_READ_SUB_SENSE_DATA) ? | 
 | 979 | 					", sense data" : "", | 
 | 980 | 				(status_buffer->status_subtype & | 
 | 981 | 					FSF_STATUS_READ_SUB_LINK_STATUS) ? | 
 | 982 | 					", link status change" : "", | 
 | 983 | 				(status_buffer->status_subtype & | 
 | 984 | 					FSF_STATUS_READ_SUB_PORT_CLOSED) ? | 
 | 985 | 					", port close" : "", | 
 | 986 | 				(status_buffer->status_subtype & | 
 | 987 | 					FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ? | 
 | 988 | 					", bit error exception" : "", | 
 | 989 | 				(status_buffer->status_subtype & | 
 | 990 | 					FSF_STATUS_READ_SUB_ACT_UPDATED) ? | 
 | 991 | 					", ACT update" : "", | 
 | 992 | 				(status_buffer->status_subtype & | 
 | 993 | 					FSF_STATUS_READ_SUB_ACT_HARDENED) ? | 
 | 994 | 					", ACT hardening" : "", | 
 | 995 | 				(status_buffer->status_subtype & | 
 | 996 | 					FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ? | 
 | 997 | 					", adapter feature change" : ""); | 
 | 998 |  | 
 | 999 | 		if (status_buffer->status_subtype & | 
 | 1000 | 		    FSF_STATUS_READ_SUB_ACT_UPDATED) | 
 | 1001 | 			zfcp_erp_adapter_access_changed(adapter); | 
 | 1002 | 		break; | 
 | 1003 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1004 | 	case FSF_STATUS_READ_CFDC_UPDATED: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1005 | 		ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1006 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 1007 | 		zfcp_erp_adapter_access_changed(adapter); | 
 | 1008 | 		break; | 
 | 1009 |  | 
 | 1010 | 	case FSF_STATUS_READ_CFDC_HARDENED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1011 | 		switch (status_buffer->status_subtype) { | 
 | 1012 | 		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1013 | 			ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1014 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 1015 | 			break; | 
 | 1016 | 		case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1017 | 			ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1018 | 				      "to the secondary SE\n", | 
 | 1019 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 1020 | 			break; | 
 | 1021 | 		default: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1022 | 			ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1023 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 1024 | 		} | 
 | 1025 | 		break; | 
 | 1026 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 1027 | 	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: | 
 | 1028 | 		debug_text_event(adapter->erp_dbf, 2, "unsol_features:"); | 
 | 1029 | 		ZFCP_LOG_INFO("List of supported features on adapter %s has " | 
 | 1030 | 			      "been changed from 0x%08X to 0x%08X\n", | 
 | 1031 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1032 | 			      *(u32*) (status_buffer->payload + 4), | 
 | 1033 | 			      *(u32*) (status_buffer->payload)); | 
 | 1034 | 		adapter->adapter_features = *(u32*) status_buffer->payload; | 
 | 1035 | 		break; | 
 | 1036 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1037 | 	default: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1038 | 		ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1039 | 				"type was received (debug info 0x%x)\n", | 
 | 1040 | 				status_buffer->status_type); | 
 | 1041 | 		ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n", | 
 | 1042 | 			       status_buffer); | 
 | 1043 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 1044 | 			      (char *) status_buffer, | 
 | 1045 | 			      sizeof (struct fsf_status_read_buffer)); | 
 | 1046 | 		break; | 
 | 1047 | 	} | 
 | 1048 | 	mempool_free(status_buffer, adapter->pool.data_status_read); | 
| Andreas Herrmann | 1db2c9c | 2005-06-13 13:20:35 +0200 | [diff] [blame] | 1049 | 	zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1050 | 	/* | 
 | 1051 | 	 * recycle buffer and start new request repeat until outbound | 
 | 1052 | 	 * queue is empty or adapter shutdown is requested | 
 | 1053 | 	 */ | 
 | 1054 | 	/* | 
 | 1055 | 	 * FIXME(qdio): | 
 | 1056 | 	 * we may wait in the req_create for 5s during shutdown, so | 
 | 1057 | 	 * qdio_cleanup will have to wait at least that long before returning | 
 | 1058 | 	 * with failure to allow us a proper cleanup under all circumstances | 
 | 1059 | 	 */ | 
 | 1060 | 	/* | 
 | 1061 | 	 * FIXME: | 
 | 1062 | 	 * allocation failure possible? (Is this code needed?) | 
 | 1063 | 	 */ | 
 | 1064 | 	retval = zfcp_fsf_status_read(adapter, 0); | 
 | 1065 | 	if (retval < 0) { | 
 | 1066 | 		ZFCP_LOG_INFO("Failed to create unsolicited status read " | 
 | 1067 | 			      "request for the adapter %s.\n", | 
 | 1068 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 1069 | 		/* temporary fix to avoid status read buffer shortage */ | 
 | 1070 | 		adapter->status_read_failed++; | 
 | 1071 | 		if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed) | 
 | 1072 | 		    < ZFCP_STATUS_READ_FAILED_THRESHOLD) { | 
 | 1073 | 			ZFCP_LOG_INFO("restart adapter %s due to status read " | 
 | 1074 | 				      "buffer shortage\n", | 
 | 1075 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 1076 | 			zfcp_erp_adapter_reopen(adapter, 0); | 
 | 1077 | 		} | 
 | 1078 | 	} | 
 | 1079 |  out: | 
 | 1080 | 	return retval; | 
 | 1081 | } | 
 | 1082 |  | 
 | 1083 | /* | 
 | 1084 |  * function:    zfcp_fsf_abort_fcp_command | 
 | 1085 |  * | 
 | 1086 |  * purpose:	tells FSF to abort a running SCSI command | 
 | 1087 |  * | 
 | 1088 |  * returns:	address of initiated FSF request | 
 | 1089 |  *		NULL - request could not be initiated | 
 | 1090 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 1091 |  * FIXME(design): should be watched by a timeout !!! | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1092 |  * FIXME(design) shouldn't this be modified to return an int | 
 | 1093 |  *               also...don't know how though | 
 | 1094 |  */ | 
 | 1095 | struct zfcp_fsf_req * | 
 | 1096 | zfcp_fsf_abort_fcp_command(unsigned long old_req_id, | 
 | 1097 | 			   struct zfcp_adapter *adapter, | 
 | 1098 | 			   struct zfcp_unit *unit, int req_flags) | 
 | 1099 | { | 
 | 1100 | 	volatile struct qdio_buffer_element *sbale; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1101 | 	struct zfcp_fsf_req *fsf_req = NULL; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1102 | 	unsigned long lock_flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1103 | 	int retval = 0; | 
 | 1104 |  | 
 | 1105 | 	/* setup new FSF request */ | 
 | 1106 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, | 
 | 1107 | 				     req_flags, adapter->pool.fsf_req_abort, | 
 | 1108 | 				     &lock_flags, &fsf_req); | 
 | 1109 | 	if (retval < 0) { | 
 | 1110 | 		ZFCP_LOG_INFO("error: Failed to create an abort command " | 
 | 1111 | 			      "request for lun 0x%016Lx on port 0x%016Lx " | 
 | 1112 | 			      "on adapter %s.\n", | 
 | 1113 | 			      unit->fcp_lun, | 
 | 1114 | 			      unit->port->wwpn, | 
 | 1115 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 1116 | 		goto out; | 
 | 1117 | 	} | 
 | 1118 |  | 
| Christof Schmitt | 951f746 | 2007-12-20 12:30:24 +0100 | [diff] [blame] | 1119 | 	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 
 | 1120 | 			&unit->status))) | 
 | 1121 | 		goto unit_blocked; | 
 | 1122 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1123 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 1124 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 1125 |         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 1126 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1127 | 	fsf_req->data = (unsigned long) unit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1128 |  | 
 | 1129 | 	/* set handles of unit and its parent port in QTCB */ | 
 | 1130 | 	fsf_req->qtcb->header.lun_handle = unit->handle; | 
 | 1131 | 	fsf_req->qtcb->header.port_handle = unit->port->handle; | 
 | 1132 |  | 
 | 1133 | 	/* set handle of request which should be aborted */ | 
 | 1134 | 	fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id; | 
 | 1135 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1136 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | 
 | 1137 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Christof Schmitt | 951f746 | 2007-12-20 12:30:24 +0100 | [diff] [blame] | 1138 | 	if (!retval) | 
 | 1139 | 		goto out; | 
 | 1140 |  | 
 | 1141 |  unit_blocked: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1142 | 		zfcp_fsf_req_free(fsf_req); | 
 | 1143 | 		fsf_req = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1144 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1145 |  out: | 
 | 1146 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 1147 | 	return fsf_req; | 
 | 1148 | } | 
 | 1149 |  | 
 | 1150 | /* | 
 | 1151 |  * function:    zfcp_fsf_abort_fcp_command_handler | 
 | 1152 |  * | 
 | 1153 |  * purpose:	is called for finished Abort FCP Command request | 
 | 1154 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 1155 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1156 |  */ | 
 | 1157 | static int | 
 | 1158 | zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) | 
 | 1159 | { | 
 | 1160 | 	int retval = -EINVAL; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1161 | 	struct zfcp_unit *unit; | 
| Christof Schmitt | 8627533 | 2007-12-20 12:30:23 +0100 | [diff] [blame] | 1162 | 	union fsf_status_qual *fsf_stat_qual = | 
 | 1163 | 		&new_fsf_req->qtcb->header.fsf_status_qual; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1164 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1165 | 	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 1166 | 		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ | 
 | 1167 | 		goto skip_fsfstatus; | 
 | 1168 | 	} | 
 | 1169 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1170 | 	unit = (struct zfcp_unit *) new_fsf_req->data; | 
 | 1171 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1172 | 	/* evaluate FSF status in QTCB */ | 
 | 1173 | 	switch (new_fsf_req->qtcb->header.fsf_status) { | 
 | 1174 |  | 
 | 1175 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Christof Schmitt | 8627533 | 2007-12-20 12:30:23 +0100 | [diff] [blame] | 1176 | 		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1177 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3, | 
 | 1178 | 					 "fsf_s_phand_nv0"); | 
 | 1179 | 			/* | 
 | 1180 | 			 * In this case a command that was sent prior to a port | 
 | 1181 | 			 * reopen was aborted (handles are different). This is | 
 | 1182 | 			 * fine. | 
 | 1183 | 			 */ | 
 | 1184 | 		} else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1185 | 			ZFCP_LOG_INFO("Temporary port identifier 0x%x for " | 
 | 1186 | 				      "port 0x%016Lx on adapter %s invalid. " | 
 | 1187 | 				      "This may happen occasionally.\n", | 
 | 1188 | 				      unit->port->handle, | 
 | 1189 | 				      unit->port->wwpn, | 
 | 1190 | 				      zfcp_get_busid_by_unit(unit)); | 
 | 1191 | 			ZFCP_LOG_INFO("status qualifier:\n"); | 
 | 1192 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | 
 | 1193 | 				      (char *) &new_fsf_req->qtcb->header. | 
 | 1194 | 				      fsf_status_qual, | 
 | 1195 | 				      sizeof (union fsf_status_qual)); | 
 | 1196 | 			/* Let's hope this sorts out the mess */ | 
 | 1197 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 1, | 
 | 1198 | 					 "fsf_s_phand_nv1"); | 
 | 1199 | 			zfcp_erp_adapter_reopen(unit->port->adapter, 0); | 
 | 1200 | 			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1201 | 		} | 
 | 1202 | 		break; | 
 | 1203 |  | 
 | 1204 | 	case FSF_LUN_HANDLE_NOT_VALID: | 
| Christof Schmitt | 8627533 | 2007-12-20 12:30:23 +0100 | [diff] [blame] | 1205 | 		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1206 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3, | 
 | 1207 | 					 "fsf_s_lhand_nv0"); | 
 | 1208 | 			/* | 
 | 1209 | 			 * In this case a command that was sent prior to a unit | 
 | 1210 | 			 * reopen was aborted (handles are different). | 
 | 1211 | 			 * This is fine. | 
 | 1212 | 			 */ | 
 | 1213 | 		} else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1214 | 			ZFCP_LOG_INFO | 
 | 1215 | 			    ("Warning: Temporary LUN identifier 0x%x of LUN " | 
 | 1216 | 			     "0x%016Lx on port 0x%016Lx on adapter %s is " | 
 | 1217 | 			     "invalid. This may happen in rare cases. " | 
 | 1218 | 			     "Trying to re-establish link.\n", | 
 | 1219 | 			     unit->handle, | 
 | 1220 | 			     unit->fcp_lun, | 
 | 1221 | 			     unit->port->wwpn, | 
 | 1222 | 			     zfcp_get_busid_by_unit(unit)); | 
 | 1223 | 			ZFCP_LOG_DEBUG("Status qualifier data:\n"); | 
 | 1224 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 1225 | 				      (char *) &new_fsf_req->qtcb->header. | 
 | 1226 | 				      fsf_status_qual, | 
 | 1227 | 				      sizeof (union fsf_status_qual)); | 
 | 1228 | 			/* Let's hope this sorts out the mess */ | 
 | 1229 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 1, | 
 | 1230 | 					 "fsf_s_lhand_nv1"); | 
 | 1231 | 			zfcp_erp_port_reopen(unit->port, 0); | 
 | 1232 | 			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1233 | 		} | 
 | 1234 | 		break; | 
 | 1235 |  | 
 | 1236 | 	case FSF_FCP_COMMAND_DOES_NOT_EXIST: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1237 | 		retval = 0; | 
 | 1238 | 		debug_text_event(new_fsf_req->adapter->erp_dbf, 3, | 
 | 1239 | 				 "fsf_s_no_exist"); | 
 | 1240 | 		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; | 
 | 1241 | 		break; | 
 | 1242 |  | 
 | 1243 | 	case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1244 | 		ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to " | 
 | 1245 | 			      "be reopened\n", unit->port->wwpn, | 
 | 1246 | 			      zfcp_get_busid_by_unit(unit)); | 
 | 1247 | 		debug_text_event(new_fsf_req->adapter->erp_dbf, 2, | 
 | 1248 | 				 "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 1249 | 		zfcp_erp_port_boxed(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1250 | 		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | 
 | 1251 | 		    | ZFCP_STATUS_FSFREQ_RETRY; | 
 | 1252 | 		break; | 
 | 1253 |  | 
 | 1254 | 	case FSF_LUN_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1255 |                 ZFCP_LOG_INFO( | 
 | 1256 |                         "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " | 
 | 1257 |                         "to be reopened\n", | 
 | 1258 |                         unit->fcp_lun, unit->port->wwpn, | 
 | 1259 |                         zfcp_get_busid_by_unit(unit)); | 
 | 1260 |                 debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 1261 | 		zfcp_erp_unit_boxed(unit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1262 |                 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | 
 | 1263 |                         | ZFCP_STATUS_FSFREQ_RETRY; | 
 | 1264 |                 break; | 
 | 1265 |  | 
 | 1266 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1267 | 		switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 
 | 1268 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1269 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 1, | 
 | 1270 | 					 "fsf_sq_ltest"); | 
| Andreas Herrmann | 65a8d4e | 2005-06-13 13:16:27 +0200 | [diff] [blame] | 1271 | 			zfcp_test_link(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1272 | 			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1273 | 			break; | 
 | 1274 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1275 | 			/* SCSI stack will escalate */ | 
 | 1276 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 1, | 
 | 1277 | 					 "fsf_sq_ulp"); | 
 | 1278 | 			new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1279 | 			break; | 
 | 1280 | 		default: | 
 | 1281 | 			ZFCP_LOG_NORMAL | 
 | 1282 | 			    ("bug: Wrong status qualifier 0x%x arrived.\n", | 
 | 1283 | 			     new_fsf_req->qtcb->header.fsf_status_qual.word[0]); | 
 | 1284 | 			debug_text_event(new_fsf_req->adapter->erp_dbf, 0, | 
 | 1285 | 					 "fsf_sq_inval:"); | 
 | 1286 | 			debug_exception(new_fsf_req->adapter->erp_dbf, 0, | 
 | 1287 | 					&new_fsf_req->qtcb->header. | 
 | 1288 | 					fsf_status_qual.word[0], sizeof (u32)); | 
 | 1289 | 			break; | 
 | 1290 | 		} | 
 | 1291 | 		break; | 
 | 1292 |  | 
 | 1293 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1294 | 		retval = 0; | 
 | 1295 | 		new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; | 
 | 1296 | 		break; | 
 | 1297 |  | 
 | 1298 | 	default: | 
 | 1299 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 1300 | 				"(debug info 0x%x)\n", | 
 | 1301 | 				new_fsf_req->qtcb->header.fsf_status); | 
 | 1302 | 		debug_text_event(new_fsf_req->adapter->erp_dbf, 0, | 
 | 1303 | 				 "fsf_s_inval:"); | 
 | 1304 | 		debug_exception(new_fsf_req->adapter->erp_dbf, 0, | 
 | 1305 | 				&new_fsf_req->qtcb->header.fsf_status, | 
 | 1306 | 				sizeof (u32)); | 
 | 1307 | 		break; | 
 | 1308 | 	} | 
 | 1309 |  skip_fsfstatus: | 
 | 1310 | 	return retval; | 
 | 1311 | } | 
 | 1312 |  | 
 | 1313 | /** | 
 | 1314 |  * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into | 
 | 1315 |  *	one SBALE | 
 | 1316 |  * Two scatter-gather lists are passed, one for the reqeust and one for the | 
 | 1317 |  * response. | 
 | 1318 |  */ | 
 | 1319 | static inline int | 
 | 1320 | zfcp_use_one_sbal(struct scatterlist *req, int req_count, | 
 | 1321 |                   struct scatterlist *resp, int resp_count) | 
 | 1322 | { | 
 | 1323 |         return ((req_count == 1) && | 
 | 1324 | 		(resp_count == 1) && | 
 | 1325 |                 (((unsigned long) zfcp_sg_to_address(&req[0]) & | 
 | 1326 | 		  PAGE_MASK) == | 
 | 1327 | 		 ((unsigned long) (zfcp_sg_to_address(&req[0]) + | 
 | 1328 | 				   req[0].length - 1) & PAGE_MASK)) && | 
 | 1329 |                 (((unsigned long) zfcp_sg_to_address(&resp[0]) & | 
 | 1330 | 		  PAGE_MASK) == | 
 | 1331 |                  ((unsigned long) (zfcp_sg_to_address(&resp[0]) + | 
 | 1332 | 				   resp[0].length - 1) & PAGE_MASK))); | 
 | 1333 | } | 
 | 1334 |  | 
 | 1335 | /** | 
 | 1336 |  * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) | 
 | 1337 |  * @ct: pointer to struct zfcp_send_ct which conatins all needed data for | 
 | 1338 |  *	the request | 
 | 1339 |  * @pool: pointer to memory pool, if non-null this pool is used to allocate | 
 | 1340 |  *	a struct zfcp_fsf_req | 
 | 1341 |  * @erp_action: pointer to erp_action, if non-null the Generic Service request | 
 | 1342 |  *	is sent within error recovery | 
 | 1343 |  */ | 
 | 1344 | int | 
 | 1345 | zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, | 
 | 1346 | 		 struct zfcp_erp_action *erp_action) | 
 | 1347 | { | 
 | 1348 | 	volatile struct qdio_buffer_element *sbale; | 
 | 1349 | 	struct zfcp_port *port; | 
 | 1350 | 	struct zfcp_adapter *adapter; | 
 | 1351 |         struct zfcp_fsf_req *fsf_req; | 
 | 1352 |         unsigned long lock_flags; | 
 | 1353 |         int bytes; | 
 | 1354 | 	int ret = 0; | 
 | 1355 |  | 
 | 1356 | 	port = ct->port; | 
 | 1357 | 	adapter = port->adapter; | 
 | 1358 |  | 
 | 1359 | 	ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, | 
 | 1360 | 				  ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 1361 | 				  pool, &lock_flags, &fsf_req); | 
 | 1362 | 	if (ret < 0) { | 
 | 1363 |                 ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for " | 
 | 1364 | 			      "adapter: %s\n", | 
 | 1365 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 1366 | 		goto failed_req; | 
 | 1367 | 	} | 
 | 1368 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1369 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 1370 |         if (zfcp_use_one_sbal(ct->req, ct->req_count, | 
 | 1371 |                               ct->resp, ct->resp_count)){ | 
 | 1372 |                 /* both request buffer and response buffer | 
 | 1373 |                    fit into one sbale each */ | 
 | 1374 |                 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | 
 | 1375 |                 sbale[2].addr = zfcp_sg_to_address(&ct->req[0]); | 
 | 1376 |                 sbale[2].length = ct->req[0].length; | 
 | 1377 |                 sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); | 
 | 1378 |                 sbale[3].length = ct->resp[0].length; | 
 | 1379 |                 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 1380 | 	} else if (adapter->adapter_features & | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1381 |                    FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | 
 | 1382 |                 /* try to use chained SBALs */ | 
 | 1383 |                 bytes = zfcp_qdio_sbals_from_sg(fsf_req, | 
 | 1384 |                                                 SBAL_FLAGS0_TYPE_WRITE_READ, | 
 | 1385 |                                                 ct->req, ct->req_count, | 
 | 1386 |                                                 ZFCP_MAX_SBALS_PER_CT_REQ); | 
 | 1387 |                 if (bytes <= 0) { | 
 | 1388 |                         ZFCP_LOG_INFO("error: creation of CT request failed " | 
 | 1389 | 				      "on adapter %s\n", | 
 | 1390 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 1391 |                         if (bytes == 0) | 
 | 1392 |                                 ret = -ENOMEM; | 
 | 1393 |                         else | 
 | 1394 |                                 ret = bytes; | 
 | 1395 |  | 
 | 1396 |                         goto failed_send; | 
 | 1397 |                 } | 
 | 1398 |                 fsf_req->qtcb->bottom.support.req_buf_length = bytes; | 
 | 1399 |                 fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | 
 | 1400 |                 bytes = zfcp_qdio_sbals_from_sg(fsf_req, | 
 | 1401 |                                                 SBAL_FLAGS0_TYPE_WRITE_READ, | 
 | 1402 |                                                 ct->resp, ct->resp_count, | 
 | 1403 |                                                 ZFCP_MAX_SBALS_PER_CT_REQ); | 
 | 1404 |                 if (bytes <= 0) { | 
 | 1405 |                         ZFCP_LOG_INFO("error: creation of CT request failed " | 
 | 1406 | 				      "on adapter %s\n", | 
 | 1407 | 				      zfcp_get_busid_by_adapter(adapter)); | 
 | 1408 |                         if (bytes == 0) | 
 | 1409 |                                 ret = -ENOMEM; | 
 | 1410 |                         else | 
 | 1411 |                                 ret = bytes; | 
 | 1412 |  | 
 | 1413 |                         goto failed_send; | 
 | 1414 |                 } | 
 | 1415 |                 fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | 
 | 1416 |         } else { | 
 | 1417 |                 /* reject send generic request */ | 
 | 1418 | 		ZFCP_LOG_INFO( | 
 | 1419 | 			"error: microcode does not support chained SBALs," | 
 | 1420 |                         "CT request too big (adapter %s)\n", | 
 | 1421 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 1422 |                 ret = -EOPNOTSUPP; | 
 | 1423 |                 goto failed_send; | 
 | 1424 |         } | 
 | 1425 |  | 
 | 1426 | 	/* settings in QTCB */ | 
 | 1427 | 	fsf_req->qtcb->header.port_handle = port->handle; | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 1428 | 	fsf_req->qtcb->bottom.support.service_class = | 
 | 1429 | 		ZFCP_FC_SERVICE_CLASS_DEFAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1430 | 	fsf_req->qtcb->bottom.support.timeout = ct->timeout; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1431 |         fsf_req->data = (unsigned long) ct; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1432 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1433 | 	zfcp_san_dbf_event_ct_request(fsf_req); | 
 | 1434 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1435 | 	if (erp_action) { | 
 | 1436 | 		erp_action->fsf_req = fsf_req; | 
 | 1437 | 		fsf_req->erp_action = erp_action; | 
 | 1438 | 		zfcp_erp_start_timer(fsf_req); | 
 | 1439 | 	} else | 
 | 1440 | 		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
 | 1441 |  | 
 | 1442 | 	ret = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1443 | 	if (ret) { | 
 | 1444 | 		ZFCP_LOG_DEBUG("error: initiation of CT request failed " | 
 | 1445 | 			       "(adapter %s, port 0x%016Lx)\n", | 
 | 1446 | 			       zfcp_get_busid_by_adapter(adapter), port->wwpn); | 
 | 1447 | 		goto failed_send; | 
 | 1448 | 	} | 
 | 1449 |  | 
 | 1450 | 	ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n", | 
 | 1451 | 		       zfcp_get_busid_by_adapter(adapter), port->wwpn); | 
 | 1452 | 	goto out; | 
 | 1453 |  | 
 | 1454 |  failed_send: | 
 | 1455 | 	zfcp_fsf_req_free(fsf_req); | 
 | 1456 |         if (erp_action != NULL) { | 
 | 1457 |                 erp_action->fsf_req = NULL; | 
 | 1458 |         } | 
 | 1459 |  failed_req: | 
 | 1460 |  out: | 
 | 1461 |         write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 1462 | 				lock_flags); | 
 | 1463 | 	return ret; | 
 | 1464 | } | 
 | 1465 |  | 
 | 1466 | /** | 
 | 1467 |  * zfcp_fsf_send_ct_handler - handler for Generic Service requests | 
 | 1468 |  * @fsf_req: pointer to struct zfcp_fsf_req | 
 | 1469 |  * | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1470 |  * Data specific for the Generic Service request is passed using | 
 | 1471 |  * fsf_req->data. There we find the pointer to struct zfcp_send_ct. | 
 | 1472 |  * Usually a specific handler for the CT request is called which is | 
 | 1473 |  * found in this structure. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1474 |  */ | 
 | 1475 | static int | 
 | 1476 | zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) | 
 | 1477 | { | 
 | 1478 | 	struct zfcp_port *port; | 
 | 1479 | 	struct zfcp_adapter *adapter; | 
 | 1480 | 	struct zfcp_send_ct *send_ct; | 
 | 1481 | 	struct fsf_qtcb_header *header; | 
 | 1482 | 	struct fsf_qtcb_bottom_support *bottom; | 
 | 1483 | 	int retval = -EINVAL; | 
 | 1484 | 	u16 subtable, rule, counter; | 
 | 1485 |  | 
 | 1486 | 	adapter = fsf_req->adapter; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1487 | 	send_ct = (struct zfcp_send_ct *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1488 | 	port = send_ct->port; | 
 | 1489 | 	header = &fsf_req->qtcb->header; | 
 | 1490 | 	bottom = &fsf_req->qtcb->bottom.support; | 
 | 1491 |  | 
 | 1492 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 
 | 1493 | 		goto skip_fsfstatus; | 
 | 1494 |  | 
 | 1495 | 	/* evaluate FSF status in QTCB */ | 
 | 1496 | 	switch (header->fsf_status) { | 
 | 1497 |  | 
 | 1498 |         case FSF_GOOD: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1499 | 		zfcp_san_dbf_event_ct_response(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1500 |                 retval = 0; | 
 | 1501 | 		break; | 
 | 1502 |  | 
 | 1503 |         case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 1504 | 		ZFCP_LOG_INFO("error: adapter %s does not support fc " | 
 | 1505 | 			      "class %d.\n", | 
 | 1506 | 			      zfcp_get_busid_by_port(port), | 
 | 1507 | 			      ZFCP_FC_SERVICE_CLASS_DEFAULT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1508 | 		/* stop operation for this adapter */ | 
 | 1509 | 		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup"); | 
 | 1510 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 1511 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1512 | 		break; | 
 | 1513 |  | 
 | 1514 |         case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1515 |                 switch (header->fsf_status_qual.word[0]){ | 
 | 1516 |                 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1517 | 			/* reopening link to port */ | 
 | 1518 | 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest"); | 
 | 1519 | 			zfcp_test_link(port); | 
 | 1520 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1521 | 			break; | 
 | 1522 |                 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1523 | 			/* ERP strategy will escalate */ | 
 | 1524 | 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); | 
 | 1525 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1526 | 			break; | 
 | 1527 |                 default: | 
 | 1528 | 			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x " | 
 | 1529 | 				      "arrived.\n", | 
 | 1530 | 				      header->fsf_status_qual.word[0]); | 
 | 1531 | 			break; | 
 | 1532 |                 } | 
 | 1533 |                 break; | 
 | 1534 |  | 
 | 1535 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1536 | 		ZFCP_LOG_NORMAL("access denied, cannot send generic service " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1537 | 				"command (adapter %s, port d_id=0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1538 | 				zfcp_get_busid_by_port(port), port->d_id); | 
 | 1539 | 		for (counter = 0; counter < 2; counter++) { | 
 | 1540 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 1541 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 1542 | 			switch (subtable) { | 
 | 1543 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 1544 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 1545 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 1546 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 1547 |        				ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 1548 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 1549 | 				break; | 
 | 1550 | 			} | 
 | 1551 | 		} | 
 | 1552 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); | 
 | 1553 | 		zfcp_erp_port_access_denied(port); | 
 | 1554 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1555 | 		break; | 
 | 1556 |  | 
 | 1557 |         case FSF_GENERIC_COMMAND_REJECTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1558 | 		ZFCP_LOG_INFO("generic service command rejected " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1559 | 			      "(adapter %s, port d_id=0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1560 | 			      zfcp_get_busid_by_port(port), port->d_id); | 
 | 1561 | 		ZFCP_LOG_INFO("status qualifier:\n"); | 
 | 1562 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | 
 | 1563 | 			      (char *) &header->fsf_status_qual, | 
 | 1564 | 			      sizeof (union fsf_status_qual)); | 
 | 1565 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej"); | 
 | 1566 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1567 | 		break; | 
 | 1568 |  | 
 | 1569 |         case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1570 | 		ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " | 
 | 1571 | 			       "0x%016Lx on adapter %s invalid. This may " | 
 | 1572 | 			       "happen occasionally.\n", port->handle, | 
 | 1573 | 			       port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 1574 | 		ZFCP_LOG_INFO("status qualifier:\n"); | 
 | 1575 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | 
 | 1576 | 			      (char *) &header->fsf_status_qual, | 
 | 1577 | 			      sizeof (union fsf_status_qual)); | 
 | 1578 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv"); | 
 | 1579 | 		zfcp_erp_adapter_reopen(adapter, 0); | 
 | 1580 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1581 | 		break; | 
 | 1582 |  | 
 | 1583 |         case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1584 | 		ZFCP_LOG_INFO("port needs to be reopened " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1585 | 			      "(adapter %s, port d_id=0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1586 | 			      zfcp_get_busid_by_port(port), port->d_id); | 
 | 1587 | 		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 1588 | 		zfcp_erp_port_boxed(port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1589 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | 
 | 1590 | 		    | ZFCP_STATUS_FSFREQ_RETRY; | 
 | 1591 | 		break; | 
 | 1592 |  | 
 | 1593 | 	/* following states should never occure, all cases avoided | 
 | 1594 | 	   in zfcp_fsf_send_ct - but who knows ... */ | 
 | 1595 | 	case FSF_PAYLOAD_SIZE_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1596 | 		ZFCP_LOG_INFO("payload size mismatch (adapter: %s, " | 
 | 1597 | 			      "req_buf_length=%d, resp_buf_length=%d)\n", | 
 | 1598 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1599 | 			      bottom->req_buf_length, bottom->resp_buf_length); | 
 | 1600 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1601 | 		break; | 
 | 1602 | 	case FSF_REQUEST_SIZE_TOO_LARGE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1603 | 		ZFCP_LOG_INFO("request size too large (adapter: %s, " | 
 | 1604 | 			      "req_buf_length=%d)\n", | 
 | 1605 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1606 | 			      bottom->req_buf_length); | 
 | 1607 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1608 | 		break; | 
 | 1609 | 	case FSF_RESPONSE_SIZE_TOO_LARGE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1610 | 		ZFCP_LOG_INFO("response size too large (adapter: %s, " | 
 | 1611 | 			      "resp_buf_length=%d)\n", | 
 | 1612 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1613 | 			      bottom->resp_buf_length); | 
 | 1614 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1615 | 		break; | 
 | 1616 | 	case FSF_SBAL_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1617 | 		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | 
 | 1618 | 			      "resp_buf_length=%d)\n", | 
 | 1619 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1620 | 			      bottom->req_buf_length, bottom->resp_buf_length); | 
 | 1621 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1622 | 		break; | 
 | 1623 |  | 
 | 1624 |        default: | 
 | 1625 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 1626 | 				"(debug info 0x%x)\n", header->fsf_status); | 
 | 1627 | 		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval:"); | 
 | 1628 | 		debug_exception(adapter->erp_dbf, 0, | 
 | 1629 | 				&header->fsf_status_qual.word[0], sizeof (u32)); | 
 | 1630 | 		break; | 
 | 1631 | 	} | 
 | 1632 |  | 
 | 1633 | skip_fsfstatus: | 
 | 1634 | 	send_ct->status = retval; | 
 | 1635 |  | 
 | 1636 | 	if (send_ct->handler != NULL) | 
 | 1637 | 		send_ct->handler(send_ct->handler_data); | 
 | 1638 |  | 
 | 1639 | 	return retval; | 
 | 1640 | } | 
 | 1641 |  | 
 | 1642 | /** | 
 | 1643 |  * zfcp_fsf_send_els - initiate an ELS command (FC-FS) | 
 | 1644 |  * @els: pointer to struct zfcp_send_els which contains all needed data for | 
 | 1645 |  *	the command. | 
 | 1646 |  */ | 
 | 1647 | int | 
 | 1648 | zfcp_fsf_send_els(struct zfcp_send_els *els) | 
 | 1649 | { | 
 | 1650 | 	volatile struct qdio_buffer_element *sbale; | 
 | 1651 | 	struct zfcp_fsf_req *fsf_req; | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 1652 | 	u32 d_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1653 | 	struct zfcp_adapter *adapter; | 
 | 1654 | 	unsigned long lock_flags; | 
 | 1655 |         int bytes; | 
 | 1656 | 	int ret = 0; | 
 | 1657 |  | 
 | 1658 | 	d_id = els->d_id; | 
 | 1659 | 	adapter = els->adapter; | 
 | 1660 |  | 
 | 1661 |         ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | 
 | 1662 | 				  ZFCP_REQ_AUTO_CLEANUP, | 
 | 1663 | 				  NULL, &lock_flags, &fsf_req); | 
 | 1664 | 	if (ret < 0) { | 
 | 1665 |                 ZFCP_LOG_INFO("error: creation of ELS request failed " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1666 | 			      "(adapter %s, port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1667 |                               zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1668 |                 goto failed_req; | 
 | 1669 | 	} | 
 | 1670 |  | 
| Christof Schmitt | 3f0ca62 | 2007-12-20 12:30:25 +0100 | [diff] [blame] | 1671 | 	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 
 | 1672 | 			&els->port->status))) { | 
 | 1673 | 		ret = -EBUSY; | 
 | 1674 | 		goto port_blocked; | 
 | 1675 | 	} | 
 | 1676 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1677 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 1678 |         if (zfcp_use_one_sbal(els->req, els->req_count, | 
 | 1679 |                               els->resp, els->resp_count)){ | 
 | 1680 |                 /* both request buffer and response buffer | 
 | 1681 |                    fit into one sbale each */ | 
 | 1682 |                 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | 
 | 1683 |                 sbale[2].addr = zfcp_sg_to_address(&els->req[0]); | 
 | 1684 |                 sbale[2].length = els->req[0].length; | 
 | 1685 |                 sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); | 
 | 1686 |                 sbale[3].length = els->resp[0].length; | 
 | 1687 |                 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 1688 | 	} else if (adapter->adapter_features & | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1689 |                    FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | 
 | 1690 |                 /* try to use chained SBALs */ | 
 | 1691 |                 bytes = zfcp_qdio_sbals_from_sg(fsf_req, | 
 | 1692 |                                                 SBAL_FLAGS0_TYPE_WRITE_READ, | 
 | 1693 |                                                 els->req, els->req_count, | 
 | 1694 |                                                 ZFCP_MAX_SBALS_PER_ELS_REQ); | 
 | 1695 |                 if (bytes <= 0) { | 
 | 1696 |                         ZFCP_LOG_INFO("error: creation of ELS request failed " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1697 | 				      "(adapter %s, port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1698 | 				      zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1699 |                         if (bytes == 0) { | 
 | 1700 |                                 ret = -ENOMEM; | 
 | 1701 |                         } else { | 
 | 1702 |                                 ret = bytes; | 
 | 1703 |                         } | 
 | 1704 |                         goto failed_send; | 
 | 1705 |                 } | 
 | 1706 |                 fsf_req->qtcb->bottom.support.req_buf_length = bytes; | 
 | 1707 |                 fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | 
 | 1708 |                 bytes = zfcp_qdio_sbals_from_sg(fsf_req, | 
 | 1709 |                                                 SBAL_FLAGS0_TYPE_WRITE_READ, | 
 | 1710 |                                                 els->resp, els->resp_count, | 
 | 1711 |                                                 ZFCP_MAX_SBALS_PER_ELS_REQ); | 
 | 1712 |                 if (bytes <= 0) { | 
 | 1713 |                         ZFCP_LOG_INFO("error: creation of ELS request failed " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1714 | 				      "(adapter %s, port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1715 | 				      zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1716 |                         if (bytes == 0) { | 
 | 1717 |                                 ret = -ENOMEM; | 
 | 1718 |                         } else { | 
 | 1719 |                                 ret = bytes; | 
 | 1720 |                         } | 
 | 1721 |                         goto failed_send; | 
 | 1722 |                 } | 
 | 1723 |                 fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | 
 | 1724 |         } else { | 
 | 1725 |                 /* reject request */ | 
 | 1726 | 		ZFCP_LOG_INFO("error: microcode does not support chained SBALs" | 
 | 1727 |                               ", ELS request too big (adapter %s, " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1728 | 			      "port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1729 | 			      zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1730 |                 ret = -EOPNOTSUPP; | 
 | 1731 |                 goto failed_send; | 
 | 1732 |         } | 
 | 1733 |  | 
 | 1734 | 	/* settings in QTCB */ | 
 | 1735 | 	fsf_req->qtcb->bottom.support.d_id = d_id; | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 1736 | 	fsf_req->qtcb->bottom.support.service_class = | 
 | 1737 | 		ZFCP_FC_SERVICE_CLASS_DEFAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1738 | 	fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1739 | 	fsf_req->data = (unsigned long) els; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1740 |  | 
 | 1741 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 1742 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1743 | 	zfcp_san_dbf_event_els_request(fsf_req); | 
 | 1744 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1745 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
 | 1746 | 	ret = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1747 | 	if (ret) { | 
 | 1748 | 		ZFCP_LOG_DEBUG("error: initiation of ELS request failed " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1749 | 			       "(adapter %s, port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1750 | 			       zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1751 | 		goto failed_send; | 
 | 1752 | 	} | 
 | 1753 |  | 
 | 1754 | 	ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1755 | 		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1756 | 	goto out; | 
 | 1757 |  | 
| Christof Schmitt | 3f0ca62 | 2007-12-20 12:30:25 +0100 | [diff] [blame] | 1758 |  port_blocked: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1759 |  failed_send: | 
 | 1760 | 	zfcp_fsf_req_free(fsf_req); | 
 | 1761 |  | 
 | 1762 |  failed_req: | 
 | 1763 |  out: | 
 | 1764 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 1765 | 				lock_flags); | 
 | 1766 |  | 
 | 1767 |         return ret; | 
 | 1768 | } | 
 | 1769 |  | 
 | 1770 | /** | 
 | 1771 |  * zfcp_fsf_send_els_handler - handler for ELS commands | 
 | 1772 |  * @fsf_req: pointer to struct zfcp_fsf_req | 
 | 1773 |  * | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1774 |  * Data specific for the ELS command is passed using | 
 | 1775 |  * fsf_req->data. There we find the pointer to struct zfcp_send_els. | 
 | 1776 |  * Usually a specific handler for the ELS command is called which is | 
 | 1777 |  * found in this structure. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1778 |  */ | 
 | 1779 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) | 
 | 1780 | { | 
 | 1781 | 	struct zfcp_adapter *adapter; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1782 | 	struct zfcp_port *port; | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 1783 | 	u32 d_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1784 | 	struct fsf_qtcb_header *header; | 
 | 1785 | 	struct fsf_qtcb_bottom_support *bottom; | 
 | 1786 | 	struct zfcp_send_els *send_els; | 
 | 1787 | 	int retval = -EINVAL; | 
 | 1788 | 	u16 subtable, rule, counter; | 
 | 1789 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 1790 | 	send_els = (struct zfcp_send_els *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1791 | 	adapter = send_els->adapter; | 
| Andreas Herrmann | 64b29a13 | 2005-06-13 13:18:56 +0200 | [diff] [blame] | 1792 | 	port = send_els->port; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1793 | 	d_id = send_els->d_id; | 
 | 1794 | 	header = &fsf_req->qtcb->header; | 
 | 1795 | 	bottom = &fsf_req->qtcb->bottom.support; | 
 | 1796 |  | 
 | 1797 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 
 | 1798 | 		goto skip_fsfstatus; | 
 | 1799 |  | 
 | 1800 | 	switch (header->fsf_status) { | 
 | 1801 |  | 
 | 1802 | 	case FSF_GOOD: | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 1803 | 		zfcp_san_dbf_event_els_response(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1804 | 		retval = 0; | 
 | 1805 | 		break; | 
 | 1806 |  | 
 | 1807 | 	case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 1808 | 		ZFCP_LOG_INFO("error: adapter %s does not support fc " | 
 | 1809 | 			      "class %d.\n", | 
 | 1810 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1811 | 			      ZFCP_FC_SERVICE_CLASS_DEFAULT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1812 | 		/* stop operation for this adapter */ | 
 | 1813 | 		debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup"); | 
 | 1814 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 1815 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1816 | 		break; | 
 | 1817 |  | 
 | 1818 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1819 | 		switch (header->fsf_status_qual.word[0]){ | 
 | 1820 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1821 | 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest"); | 
| Andreas Herrmann | 64b29a13 | 2005-06-13 13:18:56 +0200 | [diff] [blame] | 1822 | 			if (port && (send_els->ls_code != ZFCP_LS_ADISC)) | 
 | 1823 | 				zfcp_test_link(port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1824 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1825 | 			break; | 
 | 1826 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1827 | 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); | 
 | 1828 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1829 | 			retval = | 
 | 1830 | 			  zfcp_handle_els_rjt(header->fsf_status_qual.word[1], | 
 | 1831 | 					      (struct zfcp_ls_rjt_par *) | 
 | 1832 | 					      &header->fsf_status_qual.word[2]); | 
 | 1833 | 			break; | 
 | 1834 | 		case FSF_SQ_RETRY_IF_POSSIBLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1835 | 			debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry"); | 
 | 1836 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1837 | 			break; | 
 | 1838 | 		default: | 
 | 1839 | 			ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n", | 
 | 1840 | 				      header->fsf_status_qual.word[0]); | 
 | 1841 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | 
 | 1842 | 				(char*)header->fsf_status_qual.word, 16); | 
 | 1843 | 		} | 
 | 1844 | 		break; | 
 | 1845 |  | 
 | 1846 | 	case FSF_ELS_COMMAND_REJECTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1847 | 		ZFCP_LOG_INFO("ELS has been rejected because command filter " | 
 | 1848 | 			      "prohibited sending " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1849 | 			      "(adapter: %s, port d_id: 0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1850 | 			      zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1851 |  | 
 | 1852 | 		break; | 
 | 1853 |  | 
 | 1854 | 	case FSF_PAYLOAD_SIZE_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1855 | 		ZFCP_LOG_INFO( | 
 | 1856 | 			"ELS request size and ELS response size must be either " | 
 | 1857 | 			"both 0, or both greater than 0 " | 
 | 1858 | 			"(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n", | 
 | 1859 | 			zfcp_get_busid_by_adapter(adapter), | 
 | 1860 | 			bottom->req_buf_length, | 
 | 1861 | 			bottom->resp_buf_length); | 
 | 1862 | 		break; | 
 | 1863 |  | 
 | 1864 | 	case FSF_REQUEST_SIZE_TOO_LARGE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1865 | 		ZFCP_LOG_INFO( | 
 | 1866 | 			"Length of the ELS request buffer, " | 
 | 1867 | 			"specified in QTCB bottom, " | 
 | 1868 | 			"exceeds the size of the buffers " | 
 | 1869 | 			"that have been allocated for ELS request data " | 
 | 1870 | 			"(adapter: %s, req_buf_length=%d)\n", | 
 | 1871 | 			zfcp_get_busid_by_adapter(adapter), | 
 | 1872 | 			bottom->req_buf_length); | 
 | 1873 | 		break; | 
 | 1874 |  | 
 | 1875 | 	case FSF_RESPONSE_SIZE_TOO_LARGE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1876 | 		ZFCP_LOG_INFO( | 
 | 1877 | 			"Length of the ELS response buffer, " | 
 | 1878 | 			"specified in QTCB bottom, " | 
 | 1879 | 			"exceeds the size of the buffers " | 
 | 1880 | 			"that have been allocated for ELS response data " | 
 | 1881 | 			"(adapter: %s, resp_buf_length=%d)\n", | 
 | 1882 | 			zfcp_get_busid_by_adapter(adapter), | 
 | 1883 | 			bottom->resp_buf_length); | 
 | 1884 | 		break; | 
 | 1885 |  | 
 | 1886 | 	case FSF_SBAL_MISMATCH: | 
 | 1887 | 		/* should never occure, avoided in zfcp_fsf_send_els */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1888 | 		ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | 
 | 1889 | 			      "resp_buf_length=%d)\n", | 
 | 1890 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 1891 | 			      bottom->req_buf_length, bottom->resp_buf_length); | 
 | 1892 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1893 | 		break; | 
 | 1894 |  | 
 | 1895 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1896 | 		ZFCP_LOG_NORMAL("access denied, cannot send ELS command " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 1897 | 				"(adapter %s, port d_id=0x%06x)\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1898 | 				zfcp_get_busid_by_adapter(adapter), d_id); | 
 | 1899 | 		for (counter = 0; counter < 2; counter++) { | 
 | 1900 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 1901 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 1902 | 			switch (subtable) { | 
 | 1903 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 1904 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 1905 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 1906 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 1907 | 				ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 1908 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 1909 | 				break; | 
 | 1910 | 			} | 
 | 1911 | 		} | 
 | 1912 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1913 | 		if (port != NULL) | 
 | 1914 | 			zfcp_erp_port_access_denied(port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1915 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1916 | 		break; | 
 | 1917 |  | 
 | 1918 | 	default: | 
 | 1919 | 		ZFCP_LOG_NORMAL( | 
 | 1920 | 			"bug: An unknown FSF Status was presented " | 
 | 1921 | 			"(adapter: %s, fsf_status=0x%08x)\n", | 
 | 1922 | 			zfcp_get_busid_by_adapter(adapter), | 
 | 1923 | 			header->fsf_status); | 
 | 1924 | 		debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval"); | 
 | 1925 | 		debug_exception(adapter->erp_dbf, 0, | 
 | 1926 | 			&header->fsf_status_qual.word[0], sizeof(u32)); | 
 | 1927 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 1928 | 		break; | 
 | 1929 | 	} | 
 | 1930 |  | 
 | 1931 | skip_fsfstatus: | 
 | 1932 | 	send_els->status = retval; | 
 | 1933 |  | 
| Heiko Carstens | aa551da | 2007-07-18 10:55:10 +0200 | [diff] [blame] | 1934 | 	if (send_els->handler) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1935 | 		send_els->handler(send_els->handler_data); | 
 | 1936 |  | 
 | 1937 | 	return retval; | 
 | 1938 | } | 
 | 1939 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1940 | int | 
 | 1941 | zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) | 
 | 1942 | { | 
 | 1943 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1944 | 	struct zfcp_fsf_req *fsf_req; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1945 | 	struct zfcp_adapter *adapter = erp_action->adapter; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1946 | 	unsigned long lock_flags; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1947 | 	int retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1948 |  | 
 | 1949 | 	/* setup new FSF request */ | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1950 | 	retval = zfcp_fsf_req_create(adapter, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1951 | 				     FSF_QTCB_EXCHANGE_CONFIG_DATA, | 
 | 1952 | 				     ZFCP_REQ_AUTO_CLEANUP, | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1953 | 				     adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1954 | 				     &lock_flags, &fsf_req); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1955 | 	if (retval) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1956 | 		ZFCP_LOG_INFO("error: Could not create exchange configuration " | 
 | 1957 | 			      "data request for adapter %s.\n", | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1958 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 1959 | 		write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 1960 | 					lock_flags); | 
 | 1961 | 		return retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1962 | 	} | 
 | 1963 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1964 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1965 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 1966 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1967 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1968 | 	fsf_req->qtcb->bottom.config.feature_selection = | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 1969 | 			FSF_FEATURE_CFDC | | 
 | 1970 | 			FSF_FEATURE_LUN_SHARING | | 
| Maxim Shchetynin | 9eb69af | 2006-01-05 09:56:47 +0100 | [diff] [blame] | 1971 | 			FSF_FEATURE_NOTIFICATION_LOST | | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 1972 | 			FSF_FEATURE_UPDATE_ALERT; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1973 | 	fsf_req->erp_action = erp_action; | 
 | 1974 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1975 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1976 | 	zfcp_erp_start_timer(fsf_req); | 
 | 1977 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1978 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 1979 | 				lock_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1980 | 	if (retval) { | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1981 | 		ZFCP_LOG_INFO("error: Could not send exchange configuration " | 
 | 1982 | 			      "data command on the adapter %s\n", | 
 | 1983 | 			      zfcp_get_busid_by_adapter(adapter)); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 1984 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1985 | 		erp_action->fsf_req = NULL; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 1986 | 	} | 
 | 1987 | 	else | 
 | 1988 | 		ZFCP_LOG_DEBUG("exchange configuration data request initiated " | 
 | 1989 | 			       "(adapter %s)\n", | 
 | 1990 | 			       zfcp_get_busid_by_adapter(adapter)); | 
 | 1991 |  | 
 | 1992 | 	return retval; | 
 | 1993 | } | 
 | 1994 |  | 
 | 1995 | int | 
 | 1996 | zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, | 
 | 1997 | 				struct fsf_qtcb_bottom_config *data) | 
 | 1998 | { | 
 | 1999 | 	volatile struct qdio_buffer_element *sbale; | 
 | 2000 | 	struct zfcp_fsf_req *fsf_req; | 
 | 2001 | 	unsigned long lock_flags; | 
 | 2002 | 	int retval; | 
 | 2003 |  | 
 | 2004 | 	/* setup new FSF request */ | 
 | 2005 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, | 
 | 2006 | 				     0, NULL, &lock_flags, &fsf_req); | 
 | 2007 | 	if (retval) { | 
 | 2008 | 		ZFCP_LOG_INFO("error: Could not create exchange configuration " | 
 | 2009 | 			      "data request for adapter %s.\n", | 
 | 2010 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2011 | 		write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 2012 | 					lock_flags); | 
 | 2013 | 		return retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2014 | 	} | 
 | 2015 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2016 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 2017 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2018 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2019 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2020 | 	fsf_req->qtcb->bottom.config.feature_selection = | 
 | 2021 | 			FSF_FEATURE_CFDC | | 
 | 2022 | 			FSF_FEATURE_LUN_SHARING | | 
 | 2023 | 			FSF_FEATURE_NOTIFICATION_LOST | | 
 | 2024 | 			FSF_FEATURE_UPDATE_ALERT; | 
 | 2025 |  | 
 | 2026 | 	if (data) | 
 | 2027 | 		fsf_req->data = (unsigned long) data; | 
 | 2028 |  | 
 | 2029 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
 | 2030 | 	retval = zfcp_fsf_req_send(fsf_req); | 
 | 2031 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2032 | 				lock_flags); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2033 | 	if (retval) | 
 | 2034 | 		ZFCP_LOG_INFO("error: Could not send exchange configuration " | 
 | 2035 | 			      "data command on the adapter %s\n", | 
 | 2036 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2037 | 	else | 
 | 2038 | 		wait_event(fsf_req->completion_wq, | 
 | 2039 | 			   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 
 | 2040 |  | 
 | 2041 | 	zfcp_fsf_req_free(fsf_req); | 
 | 2042 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2043 | 	return retval; | 
 | 2044 | } | 
 | 2045 |  | 
 | 2046 | /** | 
 | 2047 |  * zfcp_fsf_exchange_config_evaluate | 
 | 2048 |  * @fsf_req: fsf_req which belongs to xchg config data request | 
 | 2049 |  * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1) | 
 | 2050 |  * | 
 | 2051 |  * returns: -EIO on error, 0 otherwise | 
 | 2052 |  */ | 
 | 2053 | static int | 
 | 2054 | zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | 
 | 2055 | { | 
 | 2056 | 	struct fsf_qtcb_bottom_config *bottom; | 
 | 2057 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2058 | 	struct Scsi_Host *shost = adapter->scsi_host; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2059 |  | 
 | 2060 | 	bottom = &fsf_req->qtcb->bottom.config; | 
 | 2061 | 	ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", | 
 | 2062 | 		       bottom->low_qtcb_version, bottom->high_qtcb_version); | 
 | 2063 | 	adapter->fsf_lic_version = bottom->lic_version; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2064 | 	adapter->adapter_features = bottom->adapter_features; | 
 | 2065 | 	adapter->connection_features = bottom->connection_features; | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 2066 | 	adapter->peer_wwpn = 0; | 
 | 2067 | 	adapter->peer_wwnn = 0; | 
 | 2068 | 	adapter->peer_d_id = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2069 |  | 
 | 2070 | 	if (xchg_ok) { | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2071 |  | 
 | 2072 | 		if (fsf_req->data) | 
 | 2073 | 			memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, | 
 | 2074 | 				bottom, sizeof (struct fsf_qtcb_bottom_config)); | 
 | 2075 |  | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2076 | 		fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; | 
 | 2077 | 		fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; | 
 | 2078 | 		fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; | 
 | 2079 | 		fc_host_speed(shost) = bottom->fc_link_speed; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2080 | 		fc_host_supported_classes(shost) = | 
 | 2081 | 				FC_COS_CLASS2 | FC_COS_CLASS3; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2082 | 		adapter->hydra_version = bottom->adapter_type; | 
| Andreas Herrmann | ad757cd | 2006-01-13 02:26:11 +0100 | [diff] [blame] | 2083 | 		if (fc_host_permanent_port_name(shost) == -1) | 
 | 2084 | 			fc_host_permanent_port_name(shost) = | 
 | 2085 | 				fc_host_port_name(shost); | 
 | 2086 | 		if (bottom->fc_topology == FSF_TOPO_P2P) { | 
 | 2087 | 			adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; | 
 | 2088 | 			adapter->peer_wwpn = bottom->plogi_payload.wwpn; | 
 | 2089 | 			adapter->peer_wwnn = bottom->plogi_payload.wwnn; | 
 | 2090 | 			fc_host_port_type(shost) = FC_PORTTYPE_PTP; | 
 | 2091 | 		} else if (bottom->fc_topology == FSF_TOPO_FABRIC) | 
 | 2092 | 			fc_host_port_type(shost) = FC_PORTTYPE_NPORT; | 
 | 2093 | 		else if (bottom->fc_topology == FSF_TOPO_AL) | 
 | 2094 | 			fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | 
 | 2095 | 		else | 
 | 2096 | 			fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2097 | 	} else { | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2098 | 		fc_host_node_name(shost) = 0; | 
 | 2099 | 		fc_host_port_name(shost) = 0; | 
 | 2100 | 		fc_host_port_id(shost) = 0; | 
 | 2101 | 		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | 
| Andreas Herrmann | ad757cd | 2006-01-13 02:26:11 +0100 | [diff] [blame] | 2102 | 		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2103 | 		adapter->hydra_version = 0; | 
 | 2104 | 	} | 
 | 2105 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2106 | 	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2107 | 		adapter->hardware_version = bottom->hardware_version; | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2108 | 		memcpy(fc_host_serial_number(shost), bottom->serial_number, | 
 | 2109 | 		       min(FC_SERIAL_NUMBER_SIZE, 17)); | 
 | 2110 | 		EBCASC(fc_host_serial_number(shost), | 
 | 2111 | 		       min(FC_SERIAL_NUMBER_SIZE, 17)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2112 | 	} | 
 | 2113 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2114 | 	ZFCP_LOG_NORMAL("The adapter %s reported the following " | 
 | 2115 | 			"characteristics:\n" | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2116 | 			"WWNN 0x%016Lx, " | 
 | 2117 | 			"WWPN 0x%016Lx, " | 
| Christof Schmitt | 1d589ed | 2007-05-08 11:14:41 +0200 | [diff] [blame] | 2118 | 			"S_ID 0x%06x,\n" | 
| Andreas Herrmann | 13e1e1f | 2005-09-19 16:56:17 +0200 | [diff] [blame] | 2119 | 			"adapter version 0x%x, " | 
 | 2120 | 			"LIC version 0x%x, " | 
 | 2121 | 			"FC link speed %d Gb/s\n", | 
 | 2122 | 			zfcp_get_busid_by_adapter(adapter), | 
 | 2123 | 			(wwn_t) fc_host_node_name(shost), | 
 | 2124 | 			(wwn_t) fc_host_port_name(shost), | 
 | 2125 | 			fc_host_port_id(shost), | 
 | 2126 | 			adapter->hydra_version, | 
 | 2127 | 			adapter->fsf_lic_version, | 
 | 2128 | 			fc_host_speed(shost)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2129 | 	if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { | 
 | 2130 | 		ZFCP_LOG_NORMAL("error: the adapter %s " | 
 | 2131 | 				"only supports newer control block " | 
 | 2132 | 				"versions in comparison to this device " | 
 | 2133 | 				"driver (try updated device driver)\n", | 
 | 2134 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 2135 | 		debug_text_event(adapter->erp_dbf, 0, "low_qtcb_ver"); | 
 | 2136 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2137 | 		return -EIO; | 
 | 2138 | 	} | 
 | 2139 | 	if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) { | 
 | 2140 | 		ZFCP_LOG_NORMAL("error: the adapter %s " | 
 | 2141 | 				"only supports older control block " | 
 | 2142 | 				"versions than this device driver uses" | 
 | 2143 | 				"(consider a microcode upgrade)\n", | 
 | 2144 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 2145 | 		debug_text_event(adapter->erp_dbf, 0, "high_qtcb_ver"); | 
 | 2146 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2147 | 		return -EIO; | 
 | 2148 | 	} | 
 | 2149 | 	return 0; | 
 | 2150 | } | 
 | 2151 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2152 | /** | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2153 |  * function:    zfcp_fsf_exchange_config_data_handler | 
 | 2154 |  * | 
 | 2155 |  * purpose:     is called for finished Exchange Configuration Data command | 
 | 2156 |  * | 
 | 2157 |  * returns: | 
 | 2158 |  */ | 
 | 2159 | static int | 
 | 2160 | zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) | 
 | 2161 | { | 
 | 2162 | 	struct fsf_qtcb_bottom_config *bottom; | 
 | 2163 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2164 | 	struct fsf_qtcb *qtcb = fsf_req->qtcb; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2165 |  | 
 | 2166 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 
 | 2167 | 		return -EIO; | 
 | 2168 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2169 | 	switch (qtcb->header.fsf_status) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2170 |  | 
 | 2171 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2172 | 		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1)) | 
 | 2173 | 			return -EIO; | 
 | 2174 |  | 
| Andreas Herrmann | ad757cd | 2006-01-13 02:26:11 +0100 | [diff] [blame] | 2175 | 		switch (fc_host_port_type(adapter->scsi_host)) { | 
 | 2176 | 		case FC_PORTTYPE_PTP: | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 2177 | 			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel " | 
 | 2178 | 					"configuration detected at adapter %s\n" | 
 | 2179 | 					"Peer WWNN 0x%016llx, " | 
 | 2180 | 					"peer WWPN 0x%016llx, " | 
 | 2181 | 					"peer d_id 0x%06x\n", | 
 | 2182 | 					zfcp_get_busid_by_adapter(adapter), | 
 | 2183 | 					adapter->peer_wwnn, | 
 | 2184 | 					adapter->peer_wwpn, | 
 | 2185 | 					adapter->peer_d_id); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2186 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2187 | 					"top-p-to-p"); | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 2188 | 			break; | 
| Andreas Herrmann | ad757cd | 2006-01-13 02:26:11 +0100 | [diff] [blame] | 2189 | 		case FC_PORTTYPE_NLPORT: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2190 | 			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " | 
 | 2191 | 					"topology detected at adapter %s " | 
 | 2192 | 					"unsupported, shutting down adapter\n", | 
 | 2193 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 2194 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2195 | 					 "top-al"); | 
 | 2196 | 			zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2197 | 			return -EIO; | 
| Andreas Herrmann | ad757cd | 2006-01-13 02:26:11 +0100 | [diff] [blame] | 2198 | 		case FC_PORTTYPE_NPORT: | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2199 | 			ZFCP_LOG_NORMAL("Switched fabric fibrechannel " | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2200 | 					"network detected at adapter %s.\n", | 
 | 2201 | 					zfcp_get_busid_by_adapter(adapter)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2202 | 			break; | 
 | 2203 | 		default: | 
 | 2204 | 			ZFCP_LOG_NORMAL("bug: The fibrechannel topology " | 
 | 2205 | 					"reported by the exchange " | 
 | 2206 | 					"configuration command for " | 
 | 2207 | 					"the adapter %s is not " | 
 | 2208 | 					"of a type known to the zfcp " | 
 | 2209 | 					"driver, shutting down adapter\n", | 
 | 2210 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 2211 | 			debug_text_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 2212 | 					     "unknown-topo"); | 
 | 2213 | 			zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2214 | 			return -EIO; | 
 | 2215 | 		} | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2216 | 		bottom = &qtcb->bottom.config; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2217 | 		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { | 
 | 2218 | 			ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) " | 
 | 2219 | 					"allowed by the adapter %s " | 
 | 2220 | 					"is lower than the minimum " | 
 | 2221 | 					"required by the driver (%ld bytes).\n", | 
 | 2222 | 					bottom->max_qtcb_size, | 
 | 2223 | 					zfcp_get_busid_by_adapter(adapter), | 
 | 2224 | 					sizeof(struct fsf_qtcb)); | 
 | 2225 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2226 | 					 "qtcb-size"); | 
 | 2227 | 			debug_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2228 | 				    &bottom->max_qtcb_size, sizeof (u32)); | 
 | 2229 | 			zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2230 | 			return -EIO; | 
 | 2231 | 		} | 
 | 2232 | 		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | 
 | 2233 | 				&adapter->status); | 
 | 2234 | 		break; | 
 | 2235 | 	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | 
 | 2236 | 		debug_text_event(adapter->erp_dbf, 0, "xchg-inco"); | 
 | 2237 |  | 
 | 2238 | 		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) | 
 | 2239 | 			return -EIO; | 
 | 2240 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2241 | 		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | 
 | 2242 | 				&adapter->status); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2243 |  | 
 | 2244 | 		zfcp_fsf_link_down_info_eval(adapter, | 
 | 2245 | 			&qtcb->header.fsf_status_qual.link_down_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2246 | 		break; | 
 | 2247 | 	default: | 
 | 2248 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng"); | 
 | 2249 | 		debug_event(fsf_req->adapter->erp_dbf, 0, | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2250 | 			    &fsf_req->qtcb->header.fsf_status, sizeof(u32)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2251 | 		zfcp_erp_adapter_shutdown(adapter, 0); | 
 | 2252 | 		return -EIO; | 
 | 2253 | 	} | 
 | 2254 | 	return 0; | 
 | 2255 | } | 
 | 2256 |  | 
 | 2257 | /** | 
 | 2258 |  * zfcp_fsf_exchange_port_data - request information about local port | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2259 |  * @erp_action: ERP action for the adapter for which port data is requested | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2260 |  */ | 
 | 2261 | int | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2262 | zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2263 | { | 
 | 2264 | 	volatile struct qdio_buffer_element *sbale; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2265 | 	struct zfcp_fsf_req *fsf_req; | 
 | 2266 | 	struct zfcp_adapter *adapter = erp_action->adapter; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2267 | 	unsigned long lock_flags; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2268 | 	int retval; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2269 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2270 | 	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2271 | 		ZFCP_LOG_INFO("error: exchange port data " | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2272 | 			      "command not supported by adapter %s\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2273 | 			      zfcp_get_busid_by_adapter(adapter)); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2274 | 		return -EOPNOTSUPP; | 
 | 2275 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2276 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2277 | 	/* setup new FSF request */ | 
 | 2278 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2279 | 				     ZFCP_REQ_AUTO_CLEANUP, | 
 | 2280 | 				     adapter->pool.fsf_req_erp, | 
 | 2281 | 				     &lock_flags, &fsf_req); | 
 | 2282 | 	if (retval) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2283 | 		ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 
| Joe Perches | ceb3dfb | 2008-01-26 14:11:10 +0100 | [diff] [blame] | 2284 | 			      "exchange port data request for " | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2285 | 			      "the adapter %s.\n", | 
 | 2286 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2287 | 		write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 2288 | 					lock_flags); | 
 | 2289 | 		return retval; | 
 | 2290 | 	} | 
 | 2291 |  | 
 | 2292 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 2293 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2294 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 2295 |  | 
 | 2296 | 	erp_action->fsf_req = fsf_req; | 
 | 2297 | 	fsf_req->erp_action = erp_action; | 
 | 2298 | 	zfcp_erp_start_timer(fsf_req); | 
 | 2299 |  | 
 | 2300 | 	retval = zfcp_fsf_req_send(fsf_req); | 
 | 2301 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 2302 |  | 
 | 2303 | 	if (retval) { | 
 | 2304 | 		ZFCP_LOG_INFO("error: Could not send an exchange port data " | 
 | 2305 | 			      "command on the adapter %s\n", | 
 | 2306 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2307 | 		zfcp_fsf_req_free(fsf_req); | 
 | 2308 | 		erp_action->fsf_req = NULL; | 
 | 2309 | 	} | 
 | 2310 | 	else | 
 | 2311 | 		ZFCP_LOG_DEBUG("exchange port data request initiated " | 
 | 2312 | 			       "(adapter %s)\n", | 
 | 2313 | 			       zfcp_get_busid_by_adapter(adapter)); | 
 | 2314 | 	return retval; | 
 | 2315 | } | 
 | 2316 |  | 
 | 2317 |  | 
 | 2318 | /** | 
 | 2319 |  * zfcp_fsf_exchange_port_data_sync - request information about local port | 
 | 2320 |  * and wait until information is ready | 
 | 2321 |  */ | 
 | 2322 | int | 
 | 2323 | zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, | 
 | 2324 | 				struct fsf_qtcb_bottom_port *data) | 
 | 2325 | { | 
 | 2326 | 	volatile struct qdio_buffer_element *sbale; | 
 | 2327 | 	struct zfcp_fsf_req *fsf_req; | 
 | 2328 | 	unsigned long lock_flags; | 
 | 2329 | 	int retval; | 
 | 2330 |  | 
 | 2331 | 	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | 
 | 2332 | 		ZFCP_LOG_INFO("error: exchange port data " | 
 | 2333 | 			      "command not supported by adapter %s\n", | 
 | 2334 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2335 | 		return -EOPNOTSUPP; | 
 | 2336 | 	} | 
 | 2337 |  | 
 | 2338 | 	/* setup new FSF request */ | 
 | 2339 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 
 | 2340 | 				0, NULL, &lock_flags, &fsf_req); | 
 | 2341 | 	if (retval) { | 
 | 2342 | 		ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 
| Joe Perches | ceb3dfb | 2008-01-26 14:11:10 +0100 | [diff] [blame] | 2343 | 			      "exchange port data request for " | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2344 | 			      "the adapter %s.\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2345 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2346 | 		write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 
 | 2347 | 					lock_flags); | 
| Andreas Herrmann | 2448c45 | 2005-12-01 02:50:36 +0100 | [diff] [blame] | 2348 | 		return retval; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2349 | 	} | 
 | 2350 |  | 
 | 2351 | 	if (data) | 
| Andreas Herrmann | 2448c45 | 2005-12-01 02:50:36 +0100 | [diff] [blame] | 2352 | 		fsf_req->data = (unsigned long) data; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 2353 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2354 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2355 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2356 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2357 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2358 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2359 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Andreas Herrmann | 2448c45 | 2005-12-01 02:50:36 +0100 | [diff] [blame] | 2360 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2361 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2362 | 	if (retval) | 
 | 2363 | 		ZFCP_LOG_INFO("error: Could not send an exchange port data " | 
 | 2364 | 			      "command on the adapter %s\n", | 
 | 2365 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 2366 | 	else | 
| Andreas Herrmann | 2448c45 | 2005-12-01 02:50:36 +0100 | [diff] [blame] | 2367 | 		wait_event(fsf_req->completion_wq, | 
 | 2368 | 			   fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2369 |  | 
 | 2370 | 	zfcp_fsf_req_free(fsf_req); | 
 | 2371 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2372 | 	return retval; | 
 | 2373 | } | 
 | 2374 |  | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2375 | /** | 
 | 2376 |  * zfcp_fsf_exchange_port_evaluate | 
 | 2377 |  * @fsf_req: fsf_req which belongs to xchg port data request | 
 | 2378 |  * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1) | 
 | 2379 |  */ | 
 | 2380 | static void | 
 | 2381 | zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | 
 | 2382 | { | 
 | 2383 | 	struct zfcp_adapter *adapter; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2384 | 	struct fsf_qtcb_bottom_port *bottom; | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2385 | 	struct Scsi_Host *shost; | 
 | 2386 |  | 
 | 2387 | 	adapter = fsf_req->adapter; | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2388 | 	bottom = &fsf_req->qtcb->bottom.port; | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2389 | 	shost = adapter->scsi_host; | 
 | 2390 |  | 
| Swen Schillig | 52ef11a | 2007-08-28 09:31:09 +0200 | [diff] [blame] | 2391 | 	if (fsf_req->data) | 
 | 2392 | 		memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, | 
 | 2393 | 			sizeof(struct fsf_qtcb_bottom_port)); | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2394 |  | 
 | 2395 | 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | 
 | 2396 | 		fc_host_permanent_port_name(shost) = bottom->wwpn; | 
 | 2397 | 	else | 
 | 2398 | 		fc_host_permanent_port_name(shost) = fc_host_port_name(shost); | 
 | 2399 | 	fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | 
 | 2400 | 	fc_host_supported_speeds(shost) = bottom->supported_speed; | 
 | 2401 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2402 |  | 
 | 2403 | /** | 
 | 2404 |  * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request | 
 | 2405 |  * @fsf_req: pointer to struct zfcp_fsf_req | 
 | 2406 |  */ | 
 | 2407 | static void | 
 | 2408 | zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) | 
 | 2409 | { | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2410 | 	struct zfcp_adapter *adapter; | 
 | 2411 | 	struct fsf_qtcb *qtcb; | 
 | 2412 |  | 
 | 2413 | 	adapter = fsf_req->adapter; | 
 | 2414 | 	qtcb = fsf_req->qtcb; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2415 |  | 
 | 2416 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 
 | 2417 | 		return; | 
 | 2418 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2419 | 	switch (qtcb->header.fsf_status) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2420 |         case FSF_GOOD: | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2421 | 		zfcp_fsf_exchange_port_evaluate(fsf_req, 1); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2422 | 		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2423 | 		break; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2424 | 	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | 
| Andreas Herrmann | 2f8f3ed | 2006-02-11 01:41:50 +0100 | [diff] [blame] | 2425 | 		zfcp_fsf_exchange_port_evaluate(fsf_req, 0); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2426 | 		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2427 | 		zfcp_fsf_link_down_info_eval(adapter, | 
 | 2428 | 			&qtcb->header.fsf_status_qual.link_down_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2429 |                 break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2430 |         default: | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 2431 | 		debug_text_event(adapter->erp_dbf, 0, "xchg-port-ng"); | 
 | 2432 | 		debug_event(adapter->erp_dbf, 0, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2433 | 			    &fsf_req->qtcb->header.fsf_status, sizeof(u32)); | 
 | 2434 | 	} | 
 | 2435 | } | 
 | 2436 |  | 
 | 2437 |  | 
 | 2438 | /* | 
 | 2439 |  * function:    zfcp_fsf_open_port | 
 | 2440 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 2441 |  * purpose: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2442 |  * | 
 | 2443 |  * returns:	address of initiated FSF request | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 2444 |  *		NULL - request could not be initiated | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2445 |  */ | 
 | 2446 | int | 
 | 2447 | zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | 
 | 2448 | { | 
 | 2449 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2450 | 	struct zfcp_fsf_req *fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2451 | 	unsigned long lock_flags; | 
 | 2452 | 	int retval = 0; | 
 | 2453 |  | 
 | 2454 | 	/* setup new FSF request */ | 
 | 2455 | 	retval = zfcp_fsf_req_create(erp_action->adapter, | 
 | 2456 | 				     FSF_QTCB_OPEN_PORT_WITH_DID, | 
 | 2457 | 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 2458 | 				     erp_action->adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2459 | 				     &lock_flags, &fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2460 | 	if (retval < 0) { | 
 | 2461 | 		ZFCP_LOG_INFO("error: Could not create open port request " | 
 | 2462 | 			      "for port 0x%016Lx on adapter %s.\n", | 
 | 2463 | 			      erp_action->port->wwpn, | 
 | 2464 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
 | 2465 | 		goto out; | 
 | 2466 | 	} | 
 | 2467 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2468 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2469 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2470 |         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 2471 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2472 | 	fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2473 | 	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2474 | 	fsf_req->data = (unsigned long) erp_action->port; | 
 | 2475 | 	fsf_req->erp_action = erp_action; | 
 | 2476 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2477 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2478 | 	zfcp_erp_start_timer(fsf_req); | 
 | 2479 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2480 | 	if (retval) { | 
 | 2481 | 		ZFCP_LOG_INFO("error: Could not send open port request for " | 
 | 2482 | 			      "port 0x%016Lx on adapter %s.\n", | 
 | 2483 | 			      erp_action->port->wwpn, | 
 | 2484 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2485 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2486 | 		erp_action->fsf_req = NULL; | 
 | 2487 | 		goto out; | 
 | 2488 | 	} | 
 | 2489 |  | 
 | 2490 | 	ZFCP_LOG_DEBUG("open port request initiated " | 
 | 2491 | 		       "(adapter %s,  port 0x%016Lx)\n", | 
 | 2492 | 		       zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 2493 | 		       erp_action->port->wwpn); | 
 | 2494 |  out: | 
 | 2495 | 	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | 
 | 2496 | 				lock_flags); | 
 | 2497 | 	return retval; | 
 | 2498 | } | 
 | 2499 |  | 
 | 2500 | /* | 
 | 2501 |  * function:    zfcp_fsf_open_port_handler | 
 | 2502 |  * | 
 | 2503 |  * purpose:	is called for finished Open Port command | 
 | 2504 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 2505 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2506 |  */ | 
 | 2507 | static int | 
 | 2508 | zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | 
 | 2509 | { | 
 | 2510 | 	int retval = -EINVAL; | 
 | 2511 | 	struct zfcp_port *port; | 
 | 2512 | 	struct fsf_plogi *plogi; | 
 | 2513 | 	struct fsf_qtcb_header *header; | 
 | 2514 | 	u16 subtable, rule, counter; | 
 | 2515 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 2516 | 	port = (struct zfcp_port *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2517 | 	header = &fsf_req->qtcb->header; | 
 | 2518 |  | 
 | 2519 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 2520 | 		/* don't change port status in our bookkeeping */ | 
 | 2521 | 		goto skip_fsfstatus; | 
 | 2522 | 	} | 
 | 2523 |  | 
 | 2524 | 	/* evaluate FSF status in QTCB */ | 
 | 2525 | 	switch (header->fsf_status) { | 
 | 2526 |  | 
 | 2527 | 	case FSF_PORT_ALREADY_OPEN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2528 | 		ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s " | 
 | 2529 | 				"is already open.\n", | 
 | 2530 | 				port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 2531 | 		debug_text_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 2532 | 				     "fsf_s_popen"); | 
 | 2533 | 		/* | 
 | 2534 | 		 * This is a bug, however operation should continue normally | 
 | 2535 | 		 * if it is simply ignored | 
 | 2536 | 		 */ | 
 | 2537 | 		break; | 
 | 2538 |  | 
 | 2539 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2540 | 		ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx " | 
 | 2541 | 				"on adapter %s\n", | 
 | 2542 | 				port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 2543 | 		for (counter = 0; counter < 2; counter++) { | 
 | 2544 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 2545 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 2546 | 			switch (subtable) { | 
 | 2547 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 2548 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 2549 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 2550 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 2551 | 				ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 2552 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 2553 | 				break; | 
 | 2554 | 			} | 
 | 2555 | 		} | 
 | 2556 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); | 
 | 2557 | 		zfcp_erp_port_access_denied(port); | 
 | 2558 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2559 | 		break; | 
 | 2560 |  | 
 | 2561 | 	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2562 | 		ZFCP_LOG_INFO("error: The FSF adapter is out of resources. " | 
 | 2563 | 			      "The remote port 0x%016Lx on adapter %s " | 
 | 2564 | 			      "could not be opened. Disabling it.\n", | 
 | 2565 | 			      port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 2566 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2567 | 				 "fsf_s_max_ports"); | 
 | 2568 | 		zfcp_erp_port_failed(port); | 
 | 2569 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2570 | 		break; | 
 | 2571 |  | 
 | 2572 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2573 | 		switch (header->fsf_status_qual.word[0]) { | 
 | 2574 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2575 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2576 | 					 "fsf_sq_ltest"); | 
 | 2577 | 			/* ERP strategy will escalate */ | 
 | 2578 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2579 | 			break; | 
 | 2580 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
 | 2581 | 			/* ERP strategy will escalate */ | 
 | 2582 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2583 | 					 "fsf_sq_ulp"); | 
 | 2584 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2585 | 			break; | 
 | 2586 | 		case FSF_SQ_NO_RETRY_POSSIBLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2587 | 			ZFCP_LOG_NORMAL("The remote port 0x%016Lx on " | 
 | 2588 | 					"adapter %s could not be opened. " | 
 | 2589 | 					"Disabling it.\n", | 
 | 2590 | 					port->wwpn, | 
 | 2591 | 					zfcp_get_busid_by_port(port)); | 
 | 2592 | 			debug_text_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 2593 | 					     "fsf_sq_no_retry"); | 
 | 2594 | 			zfcp_erp_port_failed(port); | 
 | 2595 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2596 | 			break; | 
 | 2597 | 		default: | 
 | 2598 | 			ZFCP_LOG_NORMAL | 
 | 2599 | 			    ("bug: Wrong status qualifier 0x%x arrived.\n", | 
 | 2600 | 			     header->fsf_status_qual.word[0]); | 
 | 2601 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2602 | 					 "fsf_sq_inval:"); | 
 | 2603 | 			debug_exception( | 
 | 2604 | 				fsf_req->adapter->erp_dbf, 0, | 
 | 2605 | 				&header->fsf_status_qual.word[0], | 
 | 2606 | 				sizeof (u32)); | 
 | 2607 | 			break; | 
 | 2608 | 		} | 
 | 2609 | 		break; | 
 | 2610 |  | 
 | 2611 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2612 | 		/* save port handle assigned by FSF */ | 
 | 2613 | 		port->handle = header->port_handle; | 
 | 2614 | 		ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s " | 
 | 2615 | 			      "was opened, it's port handle is 0x%x\n", | 
 | 2616 | 			      port->wwpn, zfcp_get_busid_by_port(port), | 
 | 2617 | 			      port->handle); | 
 | 2618 | 		/* mark port as open */ | 
 | 2619 | 		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | | 
 | 2620 | 				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 2621 | 		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 
 | 2622 | 		                  ZFCP_STATUS_COMMON_ACCESS_BOXED, | 
 | 2623 | 		                  &port->status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2624 | 		retval = 0; | 
 | 2625 | 		/* check whether D_ID has changed during open */ | 
 | 2626 | 		/* | 
 | 2627 | 		 * FIXME: This check is not airtight, as the FCP channel does | 
 | 2628 | 		 * not monitor closures of target port connections caused on | 
 | 2629 | 		 * the remote side. Thus, they might miss out on invalidating | 
 | 2630 | 		 * locally cached WWPNs (and other N_Port parameters) of gone | 
 | 2631 | 		 * target ports. So, our heroic attempt to make things safe | 
 | 2632 | 		 * could be undermined by 'open port' response data tagged with | 
 | 2633 | 		 * obsolete WWPNs. Another reason to monitor potential | 
 | 2634 | 		 * connection closures ourself at least (by interpreting | 
 | 2635 | 		 * incoming ELS' and unsolicited status). It just crosses my | 
 | 2636 | 		 * mind that one should be able to cross-check by means of | 
 | 2637 | 		 * another GID_PN straight after a port has been opened. | 
 | 2638 | 		 * Alternately, an ADISC/PDISC ELS should suffice, as well. | 
 | 2639 | 		 */ | 
 | 2640 | 		plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; | 
 | 2641 | 		if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) | 
 | 2642 | 		{ | 
 | 2643 | 			if (fsf_req->qtcb->bottom.support.els1_length < | 
| Ralph Wuerthner | 75bfc28 | 2006-05-22 18:24:33 +0200 | [diff] [blame] | 2644 | 			    sizeof (struct fsf_plogi)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2645 | 				ZFCP_LOG_INFO( | 
 | 2646 | 					"warning: insufficient length of " | 
 | 2647 | 					"PLOGI payload (%i)\n", | 
 | 2648 | 					fsf_req->qtcb->bottom.support.els1_length); | 
 | 2649 | 				debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2650 | 						 "fsf_s_short_plogi:"); | 
 | 2651 | 				/* skip sanity check and assume wwpn is ok */ | 
 | 2652 | 			} else { | 
 | 2653 | 				if (plogi->serv_param.wwpn != port->wwpn) { | 
 | 2654 | 					ZFCP_LOG_INFO("warning: d_id of port " | 
 | 2655 | 						      "0x%016Lx changed during " | 
 | 2656 | 						      "open\n", port->wwpn); | 
 | 2657 | 					debug_text_event( | 
 | 2658 | 						fsf_req->adapter->erp_dbf, 0, | 
 | 2659 | 						"fsf_s_did_change:"); | 
 | 2660 | 					atomic_clear_mask( | 
 | 2661 | 						ZFCP_STATUS_PORT_DID_DID, | 
 | 2662 | 						&port->status); | 
| Ralph Wuerthner | 75bfc28 | 2006-05-22 18:24:33 +0200 | [diff] [blame] | 2663 | 				} else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2664 | 					port->wwnn = plogi->serv_param.wwnn; | 
| Ralph Wuerthner | 75bfc28 | 2006-05-22 18:24:33 +0200 | [diff] [blame] | 2665 | 					zfcp_plogi_evaluate(port, plogi); | 
 | 2666 | 				} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2667 | 			} | 
 | 2668 | 		} | 
 | 2669 | 		break; | 
 | 2670 |  | 
 | 2671 | 	case FSF_UNKNOWN_OP_SUBTYPE: | 
 | 2672 | 		/* should never occure, subtype not set in zfcp_fsf_open_port */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2673 | 		ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, " | 
 | 2674 | 			      "op_subtype=0x%x)\n", | 
 | 2675 | 			      zfcp_get_busid_by_port(port), | 
 | 2676 | 			      fsf_req->qtcb->bottom.support.operation_subtype); | 
 | 2677 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2678 | 		break; | 
 | 2679 |  | 
 | 2680 | 	default: | 
 | 2681 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 2682 | 				"(debug info 0x%x)\n", | 
 | 2683 | 				header->fsf_status); | 
 | 2684 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 2685 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 2686 | 				&header->fsf_status, sizeof (u32)); | 
 | 2687 | 		break; | 
 | 2688 | 	} | 
 | 2689 |  | 
 | 2690 |  skip_fsfstatus: | 
 | 2691 | 	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); | 
 | 2692 | 	return retval; | 
 | 2693 | } | 
 | 2694 |  | 
 | 2695 | /* | 
 | 2696 |  * function:    zfcp_fsf_close_port | 
 | 2697 |  * | 
 | 2698 |  * purpose:     submit FSF command "close port" | 
 | 2699 |  * | 
 | 2700 |  * returns:     address of initiated FSF request | 
 | 2701 |  *              NULL - request could not be initiated | 
 | 2702 |  */ | 
 | 2703 | int | 
 | 2704 | zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) | 
 | 2705 | { | 
 | 2706 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2707 | 	struct zfcp_fsf_req *fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2708 | 	unsigned long lock_flags; | 
 | 2709 | 	int retval = 0; | 
 | 2710 |  | 
 | 2711 | 	/* setup new FSF request */ | 
 | 2712 | 	retval = zfcp_fsf_req_create(erp_action->adapter, | 
 | 2713 | 				     FSF_QTCB_CLOSE_PORT, | 
 | 2714 | 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 2715 | 				     erp_action->adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2716 | 				     &lock_flags, &fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2717 | 	if (retval < 0) { | 
 | 2718 | 		ZFCP_LOG_INFO("error: Could not create a close port request " | 
 | 2719 | 			      "for port 0x%016Lx on adapter %s.\n", | 
 | 2720 | 			      erp_action->port->wwpn, | 
 | 2721 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
 | 2722 | 		goto out; | 
 | 2723 | 	} | 
 | 2724 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2725 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2726 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2727 |         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 2728 |  | 
 | 2729 | 	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2730 | 	fsf_req->data = (unsigned long) erp_action->port; | 
 | 2731 | 	fsf_req->erp_action = erp_action; | 
 | 2732 | 	fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 
 | 2733 | 	fsf_req->erp_action = erp_action; | 
 | 2734 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2735 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2736 | 	zfcp_erp_start_timer(fsf_req); | 
 | 2737 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2738 | 	if (retval) { | 
 | 2739 | 		ZFCP_LOG_INFO("error: Could not send a close port request for " | 
 | 2740 | 			      "port 0x%016Lx on adapter %s.\n", | 
 | 2741 | 			      erp_action->port->wwpn, | 
 | 2742 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2743 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2744 | 		erp_action->fsf_req = NULL; | 
 | 2745 | 		goto out; | 
 | 2746 | 	} | 
 | 2747 |  | 
 | 2748 | 	ZFCP_LOG_TRACE("close port request initiated " | 
 | 2749 | 		       "(adapter %s, port 0x%016Lx)\n", | 
 | 2750 | 		       zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 2751 | 		       erp_action->port->wwpn); | 
 | 2752 |  out: | 
 | 2753 | 	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | 
 | 2754 | 				lock_flags); | 
 | 2755 | 	return retval; | 
 | 2756 | } | 
 | 2757 |  | 
 | 2758 | /* | 
 | 2759 |  * function:    zfcp_fsf_close_port_handler | 
 | 2760 |  * | 
 | 2761 |  * purpose:     is called for finished Close Port FSF command | 
 | 2762 |  * | 
 | 2763 |  * returns: | 
 | 2764 |  */ | 
 | 2765 | static int | 
 | 2766 | zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) | 
 | 2767 | { | 
 | 2768 | 	int retval = -EINVAL; | 
 | 2769 | 	struct zfcp_port *port; | 
 | 2770 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 2771 | 	port = (struct zfcp_port *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2772 |  | 
 | 2773 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 2774 | 		/* don't change port status in our bookkeeping */ | 
 | 2775 | 		goto skip_fsfstatus; | 
 | 2776 | 	} | 
 | 2777 |  | 
 | 2778 | 	/* evaluate FSF status in QTCB */ | 
 | 2779 | 	switch (fsf_req->qtcb->header.fsf_status) { | 
 | 2780 |  | 
 | 2781 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2782 | 		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 
 | 2783 | 			      "0x%016Lx on adapter %s invalid. This may happen " | 
 | 2784 | 			      "occasionally.\n", port->handle, | 
 | 2785 | 			      port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 2786 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 2787 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 2788 | 			      (char *) &fsf_req->qtcb->header.fsf_status_qual, | 
 | 2789 | 			      sizeof (union fsf_status_qual)); | 
 | 2790 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2791 | 				 "fsf_s_phand_nv"); | 
 | 2792 | 		zfcp_erp_adapter_reopen(port->adapter, 0); | 
 | 2793 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2794 | 		break; | 
 | 2795 |  | 
 | 2796 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2797 | 		/* Note: FSF has actually closed the port in this case. | 
 | 2798 | 		 * The status code is just daft. Fingers crossed for a change | 
 | 2799 | 		 */ | 
 | 2800 | 		retval = 0; | 
 | 2801 | 		break; | 
 | 2802 |  | 
 | 2803 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2804 | 		ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, " | 
 | 2805 | 			       "port handle 0x%x\n", port->wwpn, | 
 | 2806 | 			       zfcp_get_busid_by_port(port), port->handle); | 
 | 2807 | 		zfcp_erp_modify_port_status(port, | 
 | 2808 | 					    ZFCP_STATUS_COMMON_OPEN, | 
 | 2809 | 					    ZFCP_CLEAR); | 
 | 2810 | 		retval = 0; | 
 | 2811 | 		break; | 
 | 2812 |  | 
 | 2813 | 	default: | 
 | 2814 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 2815 | 				"(debug info 0x%x)\n", | 
 | 2816 | 				fsf_req->qtcb->header.fsf_status); | 
 | 2817 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 2818 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 2819 | 				&fsf_req->qtcb->header.fsf_status, | 
 | 2820 | 				sizeof (u32)); | 
 | 2821 | 		break; | 
 | 2822 | 	} | 
 | 2823 |  | 
 | 2824 |  skip_fsfstatus: | 
 | 2825 | 	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); | 
 | 2826 | 	return retval; | 
 | 2827 | } | 
 | 2828 |  | 
 | 2829 | /* | 
 | 2830 |  * function:    zfcp_fsf_close_physical_port | 
 | 2831 |  * | 
 | 2832 |  * purpose:     submit FSF command "close physical port" | 
 | 2833 |  * | 
 | 2834 |  * returns:     address of initiated FSF request | 
 | 2835 |  *              NULL - request could not be initiated | 
 | 2836 |  */ | 
 | 2837 | int | 
 | 2838 | zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) | 
 | 2839 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2840 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2841 | 	struct zfcp_fsf_req *fsf_req; | 
 | 2842 | 	unsigned long lock_flags; | 
 | 2843 | 	int retval = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2844 |  | 
 | 2845 | 	/* setup new FSF request */ | 
 | 2846 | 	retval = zfcp_fsf_req_create(erp_action->adapter, | 
 | 2847 | 				     FSF_QTCB_CLOSE_PHYSICAL_PORT, | 
 | 2848 | 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 2849 | 				     erp_action->adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2850 | 				     &lock_flags, &fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2851 | 	if (retval < 0) { | 
 | 2852 | 		ZFCP_LOG_INFO("error: Could not create close physical port " | 
 | 2853 | 			      "request (adapter %s, port 0x%016Lx)\n", | 
 | 2854 | 			      zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 2855 | 			      erp_action->port->wwpn); | 
 | 2856 |  | 
 | 2857 | 		goto out; | 
 | 2858 | 	} | 
 | 2859 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2860 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2861 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 2862 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 2863 |  | 
 | 2864 | 	/* mark port as being closed */ | 
 | 2865 | 	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, | 
 | 2866 | 			&erp_action->port->status); | 
 | 2867 | 	/* save a pointer to this port */ | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2868 | 	fsf_req->data = (unsigned long) erp_action->port; | 
 | 2869 | 	fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 
 | 2870 | 	fsf_req->erp_action = erp_action; | 
 | 2871 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2872 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2873 | 	zfcp_erp_start_timer(fsf_req); | 
 | 2874 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2875 | 	if (retval) { | 
 | 2876 | 		ZFCP_LOG_INFO("error: Could not send close physical port " | 
 | 2877 | 			      "request (adapter %s, port 0x%016Lx)\n", | 
 | 2878 | 			      zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 2879 | 			      erp_action->port->wwpn); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 2880 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2881 | 		erp_action->fsf_req = NULL; | 
 | 2882 | 		goto out; | 
 | 2883 | 	} | 
 | 2884 |  | 
 | 2885 | 	ZFCP_LOG_TRACE("close physical port request initiated " | 
 | 2886 | 		       "(adapter %s, port 0x%016Lx)\n", | 
 | 2887 | 		       zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 2888 | 		       erp_action->port->wwpn); | 
 | 2889 |  out: | 
 | 2890 | 	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | 
 | 2891 | 				lock_flags); | 
 | 2892 | 	return retval; | 
 | 2893 | } | 
 | 2894 |  | 
 | 2895 | /* | 
 | 2896 |  * function:    zfcp_fsf_close_physical_port_handler | 
 | 2897 |  * | 
 | 2898 |  * purpose:     is called for finished Close Physical Port FSF command | 
 | 2899 |  * | 
 | 2900 |  * returns: | 
 | 2901 |  */ | 
 | 2902 | static int | 
 | 2903 | zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) | 
 | 2904 | { | 
 | 2905 | 	int retval = -EINVAL; | 
 | 2906 | 	struct zfcp_port *port; | 
 | 2907 | 	struct zfcp_unit *unit; | 
 | 2908 | 	struct fsf_qtcb_header *header; | 
 | 2909 | 	u16 subtable, rule, counter; | 
 | 2910 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 2911 | 	port = (struct zfcp_port *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2912 | 	header = &fsf_req->qtcb->header; | 
 | 2913 |  | 
 | 2914 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 2915 | 		/* don't change port status in our bookkeeping */ | 
 | 2916 | 		goto skip_fsfstatus; | 
 | 2917 | 	} | 
 | 2918 |  | 
 | 2919 | 	/* evaluate FSF status in QTCB */ | 
 | 2920 | 	switch (header->fsf_status) { | 
 | 2921 |  | 
 | 2922 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2923 | 		ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid" | 
 | 2924 | 			      "(adapter %s, port 0x%016Lx). " | 
 | 2925 | 			      "This may happen occasionally.\n", | 
 | 2926 | 			      port->handle, | 
 | 2927 | 			      zfcp_get_busid_by_port(port), | 
 | 2928 | 			      port->wwpn); | 
 | 2929 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 2930 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 2931 | 			      (char *) &header->fsf_status_qual, | 
 | 2932 | 			      sizeof (union fsf_status_qual)); | 
 | 2933 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2934 | 				 "fsf_s_phand_nv"); | 
 | 2935 | 		zfcp_erp_adapter_reopen(port->adapter, 0); | 
 | 2936 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2937 | 		break; | 
 | 2938 |  | 
 | 2939 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2940 | 		ZFCP_LOG_NORMAL("Access denied, cannot close " | 
 | 2941 | 				"physical port 0x%016Lx on adapter %s\n", | 
 | 2942 | 				port->wwpn, zfcp_get_busid_by_port(port)); | 
 | 2943 | 		for (counter = 0; counter < 2; counter++) { | 
 | 2944 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 2945 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 2946 | 			switch (subtable) { | 
 | 2947 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 2948 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 2949 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 2950 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 2951 | 	       			ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 2952 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 2953 | 				break; | 
 | 2954 | 			} | 
 | 2955 | 		} | 
 | 2956 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); | 
 | 2957 | 		zfcp_erp_port_access_denied(port); | 
 | 2958 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2959 | 		break; | 
 | 2960 |  | 
 | 2961 | 	case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2962 | 		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter " | 
 | 2963 | 			       "%s needs to be reopened but it was attempted " | 
 | 2964 | 			       "to close it physically.\n", | 
 | 2965 | 			       port->wwpn, | 
 | 2966 | 			       zfcp_get_busid_by_port(port)); | 
 | 2967 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 2968 | 		zfcp_erp_port_boxed(port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2969 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | 
 | 2970 | 			ZFCP_STATUS_FSFREQ_RETRY; | 
 | 2971 | 		break; | 
 | 2972 |  | 
 | 2973 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2974 | 		switch (header->fsf_status_qual.word[0]) { | 
 | 2975 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2976 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2977 | 					 "fsf_sq_ltest"); | 
 | 2978 | 			/* This will now be escalated by ERP */ | 
 | 2979 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2980 | 			break; | 
 | 2981 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2982 | 			/* ERP strategy will escalate */ | 
 | 2983 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 2984 | 					 "fsf_sq_ulp"); | 
 | 2985 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 2986 | 			break; | 
 | 2987 | 		default: | 
 | 2988 | 			ZFCP_LOG_NORMAL | 
 | 2989 | 			    ("bug: Wrong status qualifier 0x%x arrived.\n", | 
 | 2990 | 			     header->fsf_status_qual.word[0]); | 
 | 2991 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 2992 | 					 "fsf_sq_inval:"); | 
 | 2993 | 			debug_exception( | 
 | 2994 | 				fsf_req->adapter->erp_dbf, 0, | 
 | 2995 | 				&header->fsf_status_qual.word[0], sizeof (u32)); | 
 | 2996 | 			break; | 
 | 2997 | 		} | 
 | 2998 | 		break; | 
 | 2999 |  | 
 | 3000 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3001 | 		ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s " | 
 | 3002 | 			       "physically closed, port handle 0x%x\n", | 
 | 3003 | 			       port->wwpn, | 
 | 3004 | 			       zfcp_get_busid_by_port(port), port->handle); | 
 | 3005 | 		/* can't use generic zfcp_erp_modify_port_status because | 
 | 3006 | 		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port | 
 | 3007 | 		 */ | 
 | 3008 | 		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 
 | 3009 | 		list_for_each_entry(unit, &port->unit_list_head, list) | 
 | 3010 | 		    atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 
 | 3011 | 		retval = 0; | 
 | 3012 | 		break; | 
 | 3013 |  | 
 | 3014 | 	default: | 
 | 3015 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 3016 | 				"(debug info 0x%x)\n", | 
 | 3017 | 				header->fsf_status); | 
 | 3018 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 3019 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 3020 | 				&header->fsf_status, sizeof (u32)); | 
 | 3021 | 		break; | 
 | 3022 | 	} | 
 | 3023 |  | 
 | 3024 |  skip_fsfstatus: | 
 | 3025 | 	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); | 
 | 3026 | 	return retval; | 
 | 3027 | } | 
 | 3028 |  | 
 | 3029 | /* | 
 | 3030 |  * function:    zfcp_fsf_open_unit | 
 | 3031 |  * | 
 | 3032 |  * purpose: | 
 | 3033 |  * | 
 | 3034 |  * returns: | 
 | 3035 |  * | 
 | 3036 |  * assumptions:	This routine does not check whether the associated | 
 | 3037 |  *		remote port has already been opened. This should be | 
 | 3038 |  *		done by calling routines. Otherwise some status | 
 | 3039 |  *		may be presented by FSF | 
 | 3040 |  */ | 
 | 3041 | int | 
 | 3042 | zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) | 
 | 3043 | { | 
 | 3044 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3045 | 	struct zfcp_fsf_req *fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3046 | 	unsigned long lock_flags; | 
 | 3047 | 	int retval = 0; | 
 | 3048 |  | 
 | 3049 | 	/* setup new FSF request */ | 
 | 3050 | 	retval = zfcp_fsf_req_create(erp_action->adapter, | 
 | 3051 | 				     FSF_QTCB_OPEN_LUN, | 
 | 3052 | 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 3053 | 				     erp_action->adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3054 | 				     &lock_flags, &fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3055 | 	if (retval < 0) { | 
 | 3056 | 		ZFCP_LOG_INFO("error: Could not create open unit request for " | 
 | 3057 | 			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 
 | 3058 | 			      erp_action->unit->fcp_lun, | 
 | 3059 | 			      erp_action->unit->port->wwpn, | 
 | 3060 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
 | 3061 | 		goto out; | 
 | 3062 | 	} | 
 | 3063 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3064 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3065 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 3066 |         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 3067 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3068 | 	fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 
 | 3069 | 	fsf_req->qtcb->bottom.support.fcp_lun =	erp_action->unit->fcp_lun; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 3070 | 	if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE)) | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3071 | 		fsf_req->qtcb->bottom.support.option = | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 3072 | 			FSF_OPEN_LUN_SUPPRESS_BOXING; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3073 | 	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3074 | 	fsf_req->data = (unsigned long) erp_action->unit; | 
 | 3075 | 	fsf_req->erp_action = erp_action; | 
 | 3076 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3077 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3078 | 	zfcp_erp_start_timer(fsf_req); | 
 | 3079 | 	retval = zfcp_fsf_req_send(erp_action->fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3080 | 	if (retval) { | 
 | 3081 | 		ZFCP_LOG_INFO("error: Could not send an open unit request " | 
 | 3082 | 			      "on the adapter %s, port 0x%016Lx for " | 
 | 3083 | 			      "unit 0x%016Lx\n", | 
 | 3084 | 			      zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 3085 | 			      erp_action->port->wwpn, | 
 | 3086 | 			      erp_action->unit->fcp_lun); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3087 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3088 | 		erp_action->fsf_req = NULL; | 
 | 3089 | 		goto out; | 
 | 3090 | 	} | 
 | 3091 |  | 
 | 3092 | 	ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, " | 
 | 3093 | 		       "port 0x%016Lx, unit 0x%016Lx)\n", | 
 | 3094 | 		       zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 3095 | 		       erp_action->port->wwpn, erp_action->unit->fcp_lun); | 
 | 3096 |  out: | 
 | 3097 | 	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | 
 | 3098 | 				lock_flags); | 
 | 3099 | 	return retval; | 
 | 3100 | } | 
 | 3101 |  | 
 | 3102 | /* | 
 | 3103 |  * function:    zfcp_fsf_open_unit_handler | 
 | 3104 |  * | 
 | 3105 |  * purpose:	is called for finished Open LUN command | 
 | 3106 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 3107 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3108 |  */ | 
 | 3109 | static int | 
 | 3110 | zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | 
 | 3111 | { | 
 | 3112 | 	int retval = -EINVAL; | 
 | 3113 | 	struct zfcp_adapter *adapter; | 
 | 3114 | 	struct zfcp_unit *unit; | 
 | 3115 | 	struct fsf_qtcb_header *header; | 
 | 3116 | 	struct fsf_qtcb_bottom_support *bottom; | 
 | 3117 | 	struct fsf_queue_designator *queue_designator; | 
 | 3118 | 	u16 subtable, rule, counter; | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 3119 | 	int exclusive, readwrite; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3120 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3121 | 	unit = (struct zfcp_unit *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3122 |  | 
 | 3123 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 3124 | 		/* don't change unit status in our bookkeeping */ | 
 | 3125 | 		goto skip_fsfstatus; | 
 | 3126 | 	} | 
 | 3127 |  | 
 | 3128 | 	adapter = fsf_req->adapter; | 
 | 3129 | 	header = &fsf_req->qtcb->header; | 
 | 3130 | 	bottom = &fsf_req->qtcb->bottom.support; | 
 | 3131 | 	queue_designator = &header->fsf_status_qual.fsf_queue_designator; | 
 | 3132 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3133 | 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 
| Heiko Carstens | b64ddf9 | 2007-05-08 11:19:57 +0200 | [diff] [blame] | 3134 | 			  ZFCP_STATUS_COMMON_ACCESS_BOXED | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3135 | 			  ZFCP_STATUS_UNIT_SHARED | | 
 | 3136 | 			  ZFCP_STATUS_UNIT_READONLY, | 
 | 3137 | 			  &unit->status); | 
 | 3138 |  | 
 | 3139 | 	/* evaluate FSF status in QTCB */ | 
 | 3140 | 	switch (header->fsf_status) { | 
 | 3141 |  | 
 | 3142 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3143 | 		ZFCP_LOG_INFO("Temporary port identifier 0x%x " | 
 | 3144 | 			      "for port 0x%016Lx on adapter %s invalid " | 
 | 3145 | 			      "This may happen occasionally\n", | 
 | 3146 | 			      unit->port->handle, | 
 | 3147 | 			      unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 
 | 3148 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 3149 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3150 | 			      (char *) &header->fsf_status_qual, | 
 | 3151 | 			      sizeof (union fsf_status_qual)); | 
 | 3152 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_ph_nv"); | 
 | 3153 | 		zfcp_erp_adapter_reopen(unit->port->adapter, 0); | 
 | 3154 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3155 | 		break; | 
 | 3156 |  | 
 | 3157 | 	case FSF_LUN_ALREADY_OPEN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3158 | 		ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on " | 
 | 3159 | 				"remote port 0x%016Lx on adapter %s twice.\n", | 
 | 3160 | 				unit->fcp_lun, | 
 | 3161 | 				unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 
 | 3162 | 		debug_text_exception(adapter->erp_dbf, 0, | 
 | 3163 | 				     "fsf_s_uopen"); | 
 | 3164 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3165 | 		break; | 
 | 3166 |  | 
 | 3167 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3168 | 		ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on " | 
 | 3169 | 				"remote port 0x%016Lx on adapter %s\n", | 
 | 3170 | 				unit->fcp_lun, unit->port->wwpn, | 
 | 3171 | 				zfcp_get_busid_by_unit(unit)); | 
 | 3172 | 		for (counter = 0; counter < 2; counter++) { | 
 | 3173 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 3174 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 3175 | 			switch (subtable) { | 
 | 3176 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 3177 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 3178 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 3179 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 3180 | 				ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 3181 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 3182 | 				break; | 
 | 3183 | 			} | 
 | 3184 | 		} | 
 | 3185 | 		debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); | 
 | 3186 | 		zfcp_erp_unit_access_denied(unit); | 
 | 3187 | 		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 
 | 3188 |                 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 
 | 3189 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3190 | 		break; | 
 | 3191 |  | 
 | 3192 | 	case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3193 | 		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 
 | 3194 | 			       "needs to be reopened\n", | 
 | 3195 | 			       unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 
 | 3196 | 		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 3197 | 		zfcp_erp_port_boxed(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3198 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | 
 | 3199 | 			ZFCP_STATUS_FSFREQ_RETRY; | 
 | 3200 | 		break; | 
 | 3201 |  | 
 | 3202 | 	case FSF_LUN_SHARING_VIOLATION: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3203 | 		if (header->fsf_status_qual.word[0] != 0) { | 
 | 3204 | 			ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port " | 
 | 3205 | 					"with WWPN 0x%Lx " | 
 | 3206 | 					"connected to the adapter %s " | 
 | 3207 | 					"is already in use in LPAR%d, CSS%d\n", | 
 | 3208 | 					unit->fcp_lun, | 
 | 3209 | 					unit->port->wwpn, | 
 | 3210 | 					zfcp_get_busid_by_unit(unit), | 
 | 3211 | 					queue_designator->hla, | 
 | 3212 | 					queue_designator->cssid); | 
 | 3213 | 		} else { | 
 | 3214 | 			subtable = header->fsf_status_qual.halfword[4]; | 
 | 3215 | 			rule = header->fsf_status_qual.halfword[5]; | 
 | 3216 | 			switch (subtable) { | 
 | 3217 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 3218 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 3219 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 3220 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 3221 | 				ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the " | 
 | 3222 | 						"remote port with WWPN 0x%Lx " | 
 | 3223 | 						"connected to the adapter %s " | 
 | 3224 | 						"is denied (%s rule %d)\n", | 
 | 3225 | 						unit->fcp_lun, | 
 | 3226 | 						unit->port->wwpn, | 
 | 3227 | 						zfcp_get_busid_by_unit(unit), | 
 | 3228 | 						zfcp_act_subtable_type[subtable], | 
 | 3229 | 						rule); | 
 | 3230 | 				break; | 
 | 3231 | 			} | 
 | 3232 | 		} | 
 | 3233 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 3234 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3235 | 			      (char *) &header->fsf_status_qual, | 
 | 3236 | 			      sizeof (union fsf_status_qual)); | 
 | 3237 | 		debug_text_event(adapter->erp_dbf, 2, | 
 | 3238 | 				 "fsf_s_l_sh_vio"); | 
 | 3239 | 		zfcp_erp_unit_access_denied(unit); | 
 | 3240 | 		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 
 | 3241 | 		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 
 | 3242 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3243 | 		break; | 
 | 3244 |  | 
 | 3245 | 	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3246 | 		ZFCP_LOG_INFO("error: The adapter ran out of resources. " | 
 | 3247 | 			      "There is no handle (temporary port identifier) " | 
 | 3248 | 			      "available for unit 0x%016Lx on port 0x%016Lx " | 
 | 3249 | 			      "on adapter %s\n", | 
 | 3250 | 			      unit->fcp_lun, | 
 | 3251 | 			      unit->port->wwpn, | 
 | 3252 | 			      zfcp_get_busid_by_unit(unit)); | 
 | 3253 | 		debug_text_event(adapter->erp_dbf, 1, | 
 | 3254 | 				 "fsf_s_max_units"); | 
 | 3255 | 		zfcp_erp_unit_failed(unit); | 
 | 3256 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3257 | 		break; | 
 | 3258 |  | 
 | 3259 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3260 | 		switch (header->fsf_status_qual.word[0]) { | 
 | 3261 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3262 | 			/* Re-establish link to port */ | 
 | 3263 | 			debug_text_event(adapter->erp_dbf, 1, | 
 | 3264 | 					 "fsf_sq_ltest"); | 
| Andreas Herrmann | 65a8d4e | 2005-06-13 13:16:27 +0200 | [diff] [blame] | 3265 | 			zfcp_test_link(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3266 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3267 | 			break; | 
 | 3268 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3269 | 			/* ERP strategy will escalate */ | 
 | 3270 | 			debug_text_event(adapter->erp_dbf, 1, | 
 | 3271 | 					 "fsf_sq_ulp"); | 
 | 3272 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3273 | 			break; | 
 | 3274 | 		default: | 
 | 3275 | 			ZFCP_LOG_NORMAL | 
 | 3276 | 			    ("bug: Wrong status qualifier 0x%x arrived.\n", | 
 | 3277 | 			     header->fsf_status_qual.word[0]); | 
 | 3278 | 			debug_text_event(adapter->erp_dbf, 0, | 
 | 3279 | 					 "fsf_sq_inval:"); | 
 | 3280 | 			debug_exception(adapter->erp_dbf, 0, | 
 | 3281 | 					&header->fsf_status_qual.word[0], | 
 | 3282 | 				sizeof (u32)); | 
 | 3283 | 		} | 
 | 3284 | 		break; | 
 | 3285 |  | 
 | 3286 | 	case FSF_INVALID_COMMAND_OPTION: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3287 | 		ZFCP_LOG_NORMAL( | 
 | 3288 | 			"Invalid option 0x%x has been specified " | 
 | 3289 | 			"in QTCB bottom sent to the adapter %s\n", | 
 | 3290 | 			bottom->option, | 
 | 3291 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 3292 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3293 | 		retval = -EINVAL; | 
 | 3294 | 		break; | 
 | 3295 |  | 
 | 3296 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3297 | 		/* save LUN handle assigned by FSF */ | 
 | 3298 | 		unit->handle = header->lun_handle; | 
 | 3299 | 		ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on " | 
 | 3300 | 			       "adapter %s opened, port handle 0x%x\n", | 
 | 3301 | 			       unit->fcp_lun, | 
 | 3302 | 			       unit->port->wwpn, | 
 | 3303 | 			       zfcp_get_busid_by_unit(unit), | 
 | 3304 | 			       unit->handle); | 
 | 3305 | 		/* mark unit as open */ | 
 | 3306 | 		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 3307 |  | 
 | 3308 | 		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && | 
 | 3309 | 		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && | 
 | 3310 | 		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) { | 
 | 3311 | 			exclusive = (bottom->lun_access_info & | 
 | 3312 | 					FSF_UNIT_ACCESS_EXCLUSIVE); | 
 | 3313 | 			readwrite = (bottom->lun_access_info & | 
 | 3314 | 					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); | 
 | 3315 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3316 | 			if (!exclusive) | 
 | 3317 | 		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, | 
 | 3318 | 						&unit->status); | 
 | 3319 |  | 
 | 3320 | 			if (!readwrite) { | 
 | 3321 |                 		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, | 
 | 3322 | 						&unit->status); | 
 | 3323 |                 		ZFCP_LOG_NORMAL("read-only access for unit " | 
 | 3324 | 						"(adapter %s, wwpn=0x%016Lx, " | 
 | 3325 | 						"fcp_lun=0x%016Lx)\n", | 
 | 3326 | 						zfcp_get_busid_by_unit(unit), | 
 | 3327 | 						unit->port->wwpn, | 
 | 3328 | 						unit->fcp_lun); | 
 | 3329 |         		} | 
 | 3330 |  | 
 | 3331 |         		if (exclusive && !readwrite) { | 
 | 3332 |                 		ZFCP_LOG_NORMAL("exclusive access of read-only " | 
 | 3333 | 						"unit not supported\n"); | 
 | 3334 | 				zfcp_erp_unit_failed(unit); | 
 | 3335 | 				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3336 | 				zfcp_erp_unit_shutdown(unit, 0); | 
 | 3337 |         		} else if (!exclusive && readwrite) { | 
 | 3338 |                 		ZFCP_LOG_NORMAL("shared access of read-write " | 
 | 3339 | 						"unit not supported\n"); | 
 | 3340 |                 		zfcp_erp_unit_failed(unit); | 
 | 3341 | 				fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3342 | 				zfcp_erp_unit_shutdown(unit, 0); | 
 | 3343 |         		} | 
 | 3344 | 		} | 
 | 3345 |  | 
 | 3346 | 		retval = 0; | 
 | 3347 | 		break; | 
 | 3348 |  | 
 | 3349 | 	default: | 
 | 3350 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 3351 | 				"(debug info 0x%x)\n", | 
 | 3352 | 				header->fsf_status); | 
 | 3353 | 		debug_text_event(adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 3354 | 		debug_exception(adapter->erp_dbf, 0, | 
 | 3355 | 				&header->fsf_status, sizeof (u32)); | 
 | 3356 | 		break; | 
 | 3357 | 	} | 
 | 3358 |  | 
 | 3359 |  skip_fsfstatus: | 
 | 3360 | 	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); | 
 | 3361 | 	return retval; | 
 | 3362 | } | 
 | 3363 |  | 
 | 3364 | /* | 
 | 3365 |  * function:    zfcp_fsf_close_unit | 
 | 3366 |  * | 
 | 3367 |  * purpose: | 
 | 3368 |  * | 
 | 3369 |  * returns:	address of fsf_req - request successfully initiated | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 3370 |  *		NULL - | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3371 |  * | 
 | 3372 |  * assumptions: This routine does not check whether the associated | 
 | 3373 |  *              remote port/lun has already been opened. This should be | 
 | 3374 |  *              done by calling routines. Otherwise some status | 
 | 3375 |  *              may be presented by FSF | 
 | 3376 |  */ | 
 | 3377 | int | 
 | 3378 | zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) | 
 | 3379 | { | 
 | 3380 | 	volatile struct qdio_buffer_element *sbale; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3381 | 	struct zfcp_fsf_req *fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3382 | 	unsigned long lock_flags; | 
 | 3383 | 	int retval = 0; | 
 | 3384 |  | 
 | 3385 | 	/* setup new FSF request */ | 
 | 3386 | 	retval = zfcp_fsf_req_create(erp_action->adapter, | 
 | 3387 | 				     FSF_QTCB_CLOSE_LUN, | 
 | 3388 | 				     ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 
 | 3389 | 				     erp_action->adapter->pool.fsf_req_erp, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3390 | 				     &lock_flags, &fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3391 | 	if (retval < 0) { | 
 | 3392 | 		ZFCP_LOG_INFO("error: Could not create close unit request for " | 
 | 3393 | 			      "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 
 | 3394 | 			      erp_action->unit->fcp_lun, | 
 | 3395 | 			      erp_action->port->wwpn, | 
 | 3396 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
 | 3397 | 		goto out; | 
 | 3398 | 	} | 
 | 3399 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3400 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3401 |         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 
 | 3402 |         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 3403 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3404 | 	fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 
 | 3405 | 	fsf_req->qtcb->header.lun_handle = erp_action->unit->handle; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3406 | 	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3407 | 	fsf_req->data = (unsigned long) erp_action->unit; | 
 | 3408 | 	fsf_req->erp_action = erp_action; | 
 | 3409 | 	erp_action->fsf_req = fsf_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3410 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3411 | 	zfcp_erp_start_timer(fsf_req); | 
 | 3412 | 	retval = zfcp_fsf_req_send(erp_action->fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3413 | 	if (retval) { | 
 | 3414 | 		ZFCP_LOG_INFO("error: Could not send a close unit request for " | 
 | 3415 | 			      "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n", | 
 | 3416 | 			      erp_action->unit->fcp_lun, | 
 | 3417 | 			      erp_action->port->wwpn, | 
 | 3418 | 			      zfcp_get_busid_by_adapter(erp_action->adapter)); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3419 | 		zfcp_fsf_req_free(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3420 | 		erp_action->fsf_req = NULL; | 
 | 3421 | 		goto out; | 
 | 3422 | 	} | 
 | 3423 |  | 
 | 3424 | 	ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, " | 
 | 3425 | 		       "port 0x%016Lx, unit 0x%016Lx)\n", | 
 | 3426 | 		       zfcp_get_busid_by_adapter(erp_action->adapter), | 
 | 3427 | 		       erp_action->port->wwpn, erp_action->unit->fcp_lun); | 
 | 3428 |  out: | 
 | 3429 | 	write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | 
 | 3430 | 				lock_flags); | 
 | 3431 | 	return retval; | 
 | 3432 | } | 
 | 3433 |  | 
 | 3434 | /* | 
 | 3435 |  * function:    zfcp_fsf_close_unit_handler | 
 | 3436 |  * | 
 | 3437 |  * purpose:     is called for finished Close LUN FSF command | 
 | 3438 |  * | 
 | 3439 |  * returns: | 
 | 3440 |  */ | 
 | 3441 | static int | 
 | 3442 | zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) | 
 | 3443 | { | 
 | 3444 | 	int retval = -EINVAL; | 
 | 3445 | 	struct zfcp_unit *unit; | 
 | 3446 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3447 | 	unit = (struct zfcp_unit *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3448 |  | 
 | 3449 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 3450 | 		/* don't change unit status in our bookkeeping */ | 
 | 3451 | 		goto skip_fsfstatus; | 
 | 3452 | 	} | 
 | 3453 |  | 
 | 3454 | 	/* evaluate FSF status in QTCB */ | 
 | 3455 | 	switch (fsf_req->qtcb->header.fsf_status) { | 
 | 3456 |  | 
 | 3457 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3458 | 		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 
 | 3459 | 			      "0x%016Lx on adapter %s invalid. This may " | 
 | 3460 | 			      "happen in rare circumstances\n", | 
 | 3461 | 			      unit->port->handle, | 
 | 3462 | 			      unit->port->wwpn, | 
 | 3463 | 			      zfcp_get_busid_by_unit(unit)); | 
 | 3464 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 3465 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3466 | 			      (char *) &fsf_req->qtcb->header.fsf_status_qual, | 
 | 3467 | 			      sizeof (union fsf_status_qual)); | 
 | 3468 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3469 | 				 "fsf_s_phand_nv"); | 
 | 3470 | 		zfcp_erp_adapter_reopen(unit->port->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3471 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3472 | 		break; | 
 | 3473 |  | 
 | 3474 | 	case FSF_LUN_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3475 | 		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit " | 
 | 3476 | 			      "0x%016Lx on port 0x%016Lx on adapter %s is " | 
 | 3477 | 			      "invalid. This may happen occasionally.\n", | 
 | 3478 | 			      unit->handle, | 
 | 3479 | 			      unit->fcp_lun, | 
 | 3480 | 			      unit->port->wwpn, | 
 | 3481 | 			      zfcp_get_busid_by_unit(unit)); | 
 | 3482 | 		ZFCP_LOG_DEBUG("Status qualifier data:\n"); | 
 | 3483 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3484 | 			      (char *) &fsf_req->qtcb->header.fsf_status_qual, | 
 | 3485 | 			      sizeof (union fsf_status_qual)); | 
 | 3486 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3487 | 				 "fsf_s_lhand_nv"); | 
 | 3488 | 		zfcp_erp_port_reopen(unit->port, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3489 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3490 | 		break; | 
 | 3491 |  | 
 | 3492 | 	case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3493 | 		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 
 | 3494 | 			       "needs to be reopened\n", | 
 | 3495 | 			       unit->port->wwpn, | 
 | 3496 | 			       zfcp_get_busid_by_unit(unit)); | 
 | 3497 | 		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 3498 | 		zfcp_erp_port_boxed(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3499 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | 
 | 3500 | 			ZFCP_STATUS_FSFREQ_RETRY; | 
 | 3501 | 		break; | 
 | 3502 |  | 
 | 3503 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3504 | 		switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 
 | 3505 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3506 | 			/* re-establish link to port */ | 
 | 3507 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3508 | 					 "fsf_sq_ltest"); | 
| Andreas Herrmann | 65a8d4e | 2005-06-13 13:16:27 +0200 | [diff] [blame] | 3509 | 			zfcp_test_link(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3510 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3511 | 			break; | 
 | 3512 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3513 | 			/* ERP strategy will escalate */ | 
 | 3514 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3515 | 					 "fsf_sq_ulp"); | 
 | 3516 | 			fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3517 | 			break; | 
 | 3518 | 		default: | 
 | 3519 | 			ZFCP_LOG_NORMAL | 
 | 3520 | 			    ("bug: Wrong status qualifier 0x%x arrived.\n", | 
 | 3521 | 			     fsf_req->qtcb->header.fsf_status_qual.word[0]); | 
 | 3522 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 3523 | 					 "fsf_sq_inval:"); | 
 | 3524 | 			debug_exception( | 
 | 3525 | 				fsf_req->adapter->erp_dbf, 0, | 
 | 3526 | 				&fsf_req->qtcb->header.fsf_status_qual.word[0], | 
 | 3527 | 				sizeof (u32)); | 
 | 3528 | 			break; | 
 | 3529 | 		} | 
 | 3530 | 		break; | 
 | 3531 |  | 
 | 3532 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3533 | 		ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s " | 
 | 3534 | 			       "closed, port handle 0x%x\n", | 
 | 3535 | 			       unit->fcp_lun, | 
 | 3536 | 			       unit->port->wwpn, | 
 | 3537 | 			       zfcp_get_busid_by_unit(unit), | 
 | 3538 | 			       unit->handle); | 
 | 3539 | 		/* mark unit as closed */ | 
 | 3540 | 		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 
 | 3541 | 		retval = 0; | 
 | 3542 | 		break; | 
 | 3543 |  | 
 | 3544 | 	default: | 
 | 3545 | 		ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | 
 | 3546 | 				"(debug info 0x%x)\n", | 
 | 3547 | 				fsf_req->qtcb->header.fsf_status); | 
 | 3548 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 3549 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 3550 | 				&fsf_req->qtcb->header.fsf_status, | 
 | 3551 | 				sizeof (u32)); | 
 | 3552 | 		break; | 
 | 3553 | 	} | 
 | 3554 |  | 
 | 3555 |  skip_fsfstatus: | 
 | 3556 | 	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); | 
 | 3557 | 	return retval; | 
 | 3558 | } | 
 | 3559 |  | 
 | 3560 | /** | 
 | 3561 |  * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) | 
 | 3562 |  * @adapter: adapter where scsi command is issued | 
 | 3563 |  * @unit: unit where command is sent to | 
 | 3564 |  * @scsi_cmnd: scsi command to be sent | 
 | 3565 |  * @timer: timer to be started when request is initiated | 
 | 3566 |  * @req_flags: flags for fsf_request | 
 | 3567 |  */ | 
 | 3568 | int | 
 | 3569 | zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, | 
 | 3570 | 			       struct zfcp_unit *unit, | 
 | 3571 | 			       struct scsi_cmnd * scsi_cmnd, | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3572 | 			       int use_timer, int req_flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3573 | { | 
 | 3574 | 	struct zfcp_fsf_req *fsf_req = NULL; | 
 | 3575 | 	struct fcp_cmnd_iu *fcp_cmnd_iu; | 
 | 3576 | 	unsigned int sbtype; | 
 | 3577 | 	unsigned long lock_flags; | 
 | 3578 | 	int real_bytes = 0; | 
 | 3579 | 	int retval = 0; | 
 | 3580 | 	int mask; | 
 | 3581 |  | 
 | 3582 | 	/* setup new FSF request */ | 
 | 3583 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | 
 | 3584 | 				     adapter->pool.fsf_req_scsi, | 
 | 3585 | 				     &lock_flags, &fsf_req); | 
 | 3586 | 	if (unlikely(retval < 0)) { | 
 | 3587 | 		ZFCP_LOG_DEBUG("error: Could not create FCP command request " | 
 | 3588 | 			       "for unit 0x%016Lx on port 0x%016Lx on " | 
 | 3589 | 			       "adapter %s\n", | 
 | 3590 | 			       unit->fcp_lun, | 
 | 3591 | 			       unit->port->wwpn, | 
 | 3592 | 			       zfcp_get_busid_by_adapter(adapter)); | 
 | 3593 | 		goto failed_req_create; | 
 | 3594 | 	} | 
 | 3595 |  | 
| Christof Schmitt | ba17242 | 2007-12-20 12:30:26 +0100 | [diff] [blame] | 3596 | 	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 
 | 3597 | 			&unit->status))) { | 
 | 3598 | 		retval = -EBUSY; | 
 | 3599 | 		goto unit_blocked; | 
 | 3600 | 	} | 
 | 3601 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3602 | 	zfcp_unit_get(unit); | 
 | 3603 | 	fsf_req->unit = unit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3604 |  | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3605 | 	/* associate FSF request with SCSI request (for look up on abort) */ | 
| Andreas Herrmann | 4eff4a3 | 2006-09-18 22:29:20 +0200 | [diff] [blame] | 3606 | 	scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3607 |  | 
 | 3608 | 	/* associate SCSI command with FSF request */ | 
 | 3609 | 	fsf_req->data = (unsigned long) scsi_cmnd; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3610 |  | 
 | 3611 | 	/* set handles of unit and its parent port in QTCB */ | 
 | 3612 | 	fsf_req->qtcb->header.lun_handle = unit->handle; | 
 | 3613 | 	fsf_req->qtcb->header.port_handle = unit->port->handle; | 
 | 3614 |  | 
 | 3615 | 	/* FSF does not define the structure of the FCP_CMND IU */ | 
 | 3616 | 	fcp_cmnd_iu = (struct fcp_cmnd_iu *) | 
 | 3617 | 	    &(fsf_req->qtcb->bottom.io.fcp_cmnd); | 
 | 3618 |  | 
 | 3619 | 	/* | 
 | 3620 | 	 * set depending on data direction: | 
 | 3621 | 	 *      data direction bits in SBALE (SB Type) | 
 | 3622 | 	 *      data direction bits in QTCB | 
 | 3623 | 	 *      data direction bits in FCP_CMND IU | 
 | 3624 | 	 */ | 
 | 3625 | 	switch (scsi_cmnd->sc_data_direction) { | 
 | 3626 | 	case DMA_NONE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3627 | 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | 
 | 3628 | 		/* | 
 | 3629 | 		 * FIXME(qdio): | 
 | 3630 | 		 * what is the correct type for commands | 
 | 3631 | 		 * without 'real' data buffers? | 
 | 3632 | 		 */ | 
 | 3633 | 		sbtype = SBAL_FLAGS0_TYPE_READ; | 
 | 3634 | 		break; | 
 | 3635 | 	case DMA_FROM_DEVICE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3636 | 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | 
 | 3637 | 		sbtype = SBAL_FLAGS0_TYPE_READ; | 
 | 3638 | 		fcp_cmnd_iu->rddata = 1; | 
 | 3639 | 		break; | 
 | 3640 | 	case DMA_TO_DEVICE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3641 | 		fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; | 
 | 3642 | 		sbtype = SBAL_FLAGS0_TYPE_WRITE; | 
 | 3643 | 		fcp_cmnd_iu->wddata = 1; | 
 | 3644 | 		break; | 
 | 3645 | 	case DMA_BIDIRECTIONAL: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3646 | 	default: | 
 | 3647 | 		/* | 
 | 3648 | 		 * dummy, catch this condition earlier | 
 | 3649 | 		 * in zfcp_scsi_queuecommand | 
 | 3650 | 		 */ | 
 | 3651 | 		goto failed_scsi_cmnd; | 
 | 3652 | 	} | 
 | 3653 |  | 
 | 3654 | 	/* set FC service class in QTCB (3 per default) */ | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 3655 | 	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3656 |  | 
 | 3657 | 	/* set FCP_LUN in FCP_CMND IU in QTCB */ | 
 | 3658 | 	fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | 
 | 3659 |  | 
 | 3660 | 	mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED; | 
 | 3661 |  | 
 | 3662 | 	/* set task attributes in FCP_CMND IU in QTCB */ | 
 | 3663 | 	if (likely((scsi_cmnd->device->simple_tags) || | 
 | 3664 | 		   (atomic_test_mask(mask, &unit->status)))) | 
 | 3665 | 		fcp_cmnd_iu->task_attribute = SIMPLE_Q; | 
 | 3666 | 	else | 
 | 3667 | 		fcp_cmnd_iu->task_attribute = UNTAGGED; | 
 | 3668 |  | 
 | 3669 | 	/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ | 
 | 3670 | 	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { | 
 | 3671 | 		fcp_cmnd_iu->add_fcp_cdb_length | 
 | 3672 | 		    = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; | 
 | 3673 | 		ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " | 
 | 3674 | 			       "additional FCP_CDB length is 0x%x " | 
 | 3675 | 			       "(shifted right 2 bits)\n", | 
 | 3676 | 			       scsi_cmnd->cmd_len, | 
 | 3677 | 			       fcp_cmnd_iu->add_fcp_cdb_length); | 
 | 3678 | 	} | 
 | 3679 | 	/* | 
 | 3680 | 	 * copy SCSI CDB (including additional length, if any) to | 
 | 3681 | 	 * FCP_CDB in FCP_CMND IU in QTCB | 
 | 3682 | 	 */ | 
 | 3683 | 	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | 
 | 3684 |  | 
 | 3685 | 	/* FCP CMND IU length in QTCB */ | 
 | 3686 | 	fsf_req->qtcb->bottom.io.fcp_cmnd_length = | 
 | 3687 | 		sizeof (struct fcp_cmnd_iu) + | 
 | 3688 | 		fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t); | 
 | 3689 |  | 
 | 3690 | 	/* generate SBALEs from data buffer */ | 
 | 3691 | 	real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd); | 
 | 3692 | 	if (unlikely(real_bytes < 0)) { | 
 | 3693 | 		if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) { | 
 | 3694 | 			ZFCP_LOG_DEBUG( | 
 | 3695 | 				"Data did not fit into available buffer(s), " | 
 | 3696 | 			       "waiting for more...\n"); | 
| Christof Schmitt | 2282f65 | 2007-08-28 09:30:22 +0200 | [diff] [blame] | 3697 | 			retval = -EIO; | 
 | 3698 | 		} else { | 
 | 3699 | 			ZFCP_LOG_NORMAL("error: No truncation implemented but " | 
 | 3700 | 					"required. Shutting down unit " | 
 | 3701 | 					"(adapter %s, port 0x%016Lx, " | 
 | 3702 | 					"unit 0x%016Lx)\n", | 
 | 3703 | 					zfcp_get_busid_by_unit(unit), | 
 | 3704 | 					unit->port->wwpn, | 
 | 3705 | 					unit->fcp_lun); | 
 | 3706 | 			zfcp_erp_unit_shutdown(unit, 0); | 
 | 3707 | 			retval = -EINVAL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3708 | 		} | 
 | 3709 | 		goto no_fit; | 
 | 3710 | 	} | 
 | 3711 |  | 
 | 3712 | 	/* set length of FCP data length in FCP_CMND IU in QTCB */ | 
 | 3713 | 	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); | 
 | 3714 |  | 
 | 3715 | 	ZFCP_LOG_DEBUG("Sending SCSI command:\n"); | 
 | 3716 | 	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3717 | 		      (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | 
 | 3718 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3719 | 	if (use_timer) | 
 | 3720 | 		zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
 | 3721 |  | 
 | 3722 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3723 | 	if (unlikely(retval < 0)) { | 
 | 3724 | 		ZFCP_LOG_INFO("error: Could not send FCP command request " | 
 | 3725 | 			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", | 
 | 3726 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 3727 | 			      unit->port->wwpn, | 
 | 3728 | 			      unit->fcp_lun); | 
 | 3729 | 		goto send_failed; | 
 | 3730 | 	} | 
 | 3731 |  | 
 | 3732 | 	ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, " | 
 | 3733 | 		       "port 0x%016Lx, unit 0x%016Lx)\n", | 
 | 3734 | 		       zfcp_get_busid_by_adapter(adapter), | 
 | 3735 | 		       unit->port->wwpn, | 
 | 3736 | 		       unit->fcp_lun); | 
 | 3737 | 	goto success; | 
 | 3738 |  | 
 | 3739 |  send_failed: | 
 | 3740 |  no_fit: | 
 | 3741 |  failed_scsi_cmnd: | 
| Christof Schmitt | ba17242 | 2007-12-20 12:30:26 +0100 | [diff] [blame] | 3742 |  unit_blocked: | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3743 | 	zfcp_unit_put(unit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3744 | 	zfcp_fsf_req_free(fsf_req); | 
 | 3745 | 	fsf_req = NULL; | 
 | 3746 | 	scsi_cmnd->host_scribble = NULL; | 
 | 3747 |  success: | 
 | 3748 |  failed_req_create: | 
 | 3749 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 3750 | 	return retval; | 
 | 3751 | } | 
 | 3752 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3753 | struct zfcp_fsf_req * | 
 | 3754 | zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, | 
 | 3755 | 					  struct zfcp_unit *unit, | 
 | 3756 | 					  u8 tm_flags, int req_flags) | 
 | 3757 | { | 
 | 3758 | 	struct zfcp_fsf_req *fsf_req = NULL; | 
 | 3759 | 	int retval = 0; | 
 | 3760 | 	struct fcp_cmnd_iu *fcp_cmnd_iu; | 
 | 3761 | 	unsigned long lock_flags; | 
 | 3762 | 	volatile struct qdio_buffer_element *sbale; | 
 | 3763 |  | 
 | 3764 | 	/* setup new FSF request */ | 
 | 3765 | 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | 
 | 3766 | 				     adapter->pool.fsf_req_scsi, | 
 | 3767 | 				     &lock_flags, &fsf_req); | 
 | 3768 | 	if (retval < 0) { | 
 | 3769 | 		ZFCP_LOG_INFO("error: Could not create FCP command (task " | 
 | 3770 | 			      "management) request for adapter %s, port " | 
 | 3771 | 			      " 0x%016Lx, unit 0x%016Lx.\n", | 
 | 3772 | 			      zfcp_get_busid_by_adapter(adapter), | 
 | 3773 | 			      unit->port->wwpn, unit->fcp_lun); | 
 | 3774 | 		goto out; | 
 | 3775 | 	} | 
 | 3776 |  | 
| Christof Schmitt | fdf2345 | 2007-12-20 12:30:27 +0100 | [diff] [blame] | 3777 | 	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 
 | 3778 | 			&unit->status))) | 
 | 3779 | 		goto unit_blocked; | 
 | 3780 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3781 | 	/* | 
 | 3782 | 	 * Used to decide on proper handler in the return path, | 
 | 3783 | 	 * could be either zfcp_fsf_send_fcp_command_task_handler or | 
 | 3784 | 	 * zfcp_fsf_send_fcp_command_task_management_handler */ | 
 | 3785 |  | 
 | 3786 | 	fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; | 
 | 3787 |  | 
 | 3788 | 	/* | 
 | 3789 | 	 * hold a pointer to the unit being target of this | 
 | 3790 | 	 * task management request | 
 | 3791 | 	 */ | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3792 | 	fsf_req->data = (unsigned long) unit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3793 |  | 
 | 3794 | 	/* set FSF related fields in QTCB */ | 
 | 3795 | 	fsf_req->qtcb->header.lun_handle = unit->handle; | 
 | 3796 | 	fsf_req->qtcb->header.port_handle = unit->port->handle; | 
 | 3797 | 	fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 3798 | 	fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3799 | 	fsf_req->qtcb->bottom.io.fcp_cmnd_length = | 
 | 3800 | 		sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); | 
 | 3801 |  | 
 | 3802 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 3803 | 	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; | 
 | 3804 | 	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 3805 |  | 
 | 3806 | 	/* set FCP related fields in FCP_CMND IU in QTCB */ | 
 | 3807 | 	fcp_cmnd_iu = (struct fcp_cmnd_iu *) | 
 | 3808 | 		&(fsf_req->qtcb->bottom.io.fcp_cmnd); | 
 | 3809 | 	fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | 
 | 3810 | 	fcp_cmnd_iu->task_management_flags = tm_flags; | 
 | 3811 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 3812 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | 
 | 3813 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Christof Schmitt | fdf2345 | 2007-12-20 12:30:27 +0100 | [diff] [blame] | 3814 | 	if (!retval) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3815 | 		goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3816 |  | 
| Christof Schmitt | fdf2345 | 2007-12-20 12:30:27 +0100 | [diff] [blame] | 3817 |  unit_blocked: | 
 | 3818 | 	zfcp_fsf_req_free(fsf_req); | 
 | 3819 | 	fsf_req = NULL; | 
 | 3820 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3821 |  out: | 
 | 3822 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 3823 | 	return fsf_req; | 
 | 3824 | } | 
 | 3825 |  | 
 | 3826 | /* | 
 | 3827 |  * function:    zfcp_fsf_send_fcp_command_handler | 
 | 3828 |  * | 
 | 3829 |  * purpose:	is called for finished Send FCP Command | 
 | 3830 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 3831 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3832 |  */ | 
 | 3833 | static int | 
 | 3834 | zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) | 
 | 3835 | { | 
 | 3836 | 	int retval = -EINVAL; | 
 | 3837 | 	struct zfcp_unit *unit; | 
 | 3838 | 	struct fsf_qtcb_header *header; | 
 | 3839 | 	u16 subtable, rule, counter; | 
 | 3840 |  | 
 | 3841 | 	header = &fsf_req->qtcb->header; | 
 | 3842 |  | 
 | 3843 | 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3844 | 		unit = (struct zfcp_unit *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3845 | 	else | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 3846 | 		unit = fsf_req->unit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3847 |  | 
 | 3848 | 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 
 | 3849 | 		/* go directly to calls of special handlers */ | 
 | 3850 | 		goto skip_fsfstatus; | 
 | 3851 | 	} | 
 | 3852 |  | 
 | 3853 | 	/* evaluate FSF status in QTCB */ | 
 | 3854 | 	switch (header->fsf_status) { | 
 | 3855 |  | 
 | 3856 | 	case FSF_PORT_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3857 | 		ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 
 | 3858 | 			      "0x%016Lx on adapter %s invalid\n", | 
 | 3859 | 			      unit->port->handle, | 
 | 3860 | 			      unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 
 | 3861 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3862 | 			      (char *) &header->fsf_status_qual, | 
 | 3863 | 			      sizeof (union fsf_status_qual)); | 
 | 3864 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3865 | 				 "fsf_s_phand_nv"); | 
 | 3866 | 		zfcp_erp_adapter_reopen(unit->port->adapter, 0); | 
 | 3867 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3868 | 		break; | 
 | 3869 |  | 
 | 3870 | 	case FSF_LUN_HANDLE_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3871 | 		ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit " | 
 | 3872 | 			      "0x%016Lx on port 0x%016Lx on adapter %s is " | 
 | 3873 | 			      "invalid. This may happen occasionally.\n", | 
 | 3874 | 			      unit->handle, | 
 | 3875 | 			      unit->fcp_lun, | 
 | 3876 | 			      unit->port->wwpn, | 
 | 3877 | 			      zfcp_get_busid_by_unit(unit)); | 
 | 3878 | 		ZFCP_LOG_NORMAL("Status qualifier data:\n"); | 
 | 3879 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 
 | 3880 | 			      (char *) &header->fsf_status_qual, | 
 | 3881 | 			      sizeof (union fsf_status_qual)); | 
 | 3882 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3883 | 				 "fsf_s_uhand_nv"); | 
 | 3884 | 		zfcp_erp_port_reopen(unit->port, 0); | 
 | 3885 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3886 | 		break; | 
 | 3887 |  | 
 | 3888 | 	case FSF_HANDLE_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3889 | 		ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed " | 
 | 3890 | 				"unexpectedly. (adapter %s, port 0x%016Lx, " | 
 | 3891 | 				"unit 0x%016Lx)\n", | 
 | 3892 | 				unit->port->handle, | 
 | 3893 | 				zfcp_get_busid_by_unit(unit), | 
 | 3894 | 				unit->port->wwpn, | 
 | 3895 | 				unit->fcp_lun); | 
 | 3896 | 		ZFCP_LOG_NORMAL("status qualifier:\n"); | 
 | 3897 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 
 | 3898 | 			      (char *) &header->fsf_status_qual, | 
 | 3899 | 			      sizeof (union fsf_status_qual)); | 
 | 3900 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3901 | 				 "fsf_s_hand_mis"); | 
 | 3902 | 		zfcp_erp_adapter_reopen(unit->port->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3903 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3904 | 		break; | 
 | 3905 |  | 
 | 3906 | 	case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 
| Andreas Herrmann | 06506d0 | 2006-05-22 18:18:19 +0200 | [diff] [blame] | 3907 | 		ZFCP_LOG_INFO("error: adapter %s does not support fc " | 
 | 3908 | 			      "class %d.\n", | 
 | 3909 | 			      zfcp_get_busid_by_unit(unit), | 
 | 3910 | 			      ZFCP_FC_SERVICE_CLASS_DEFAULT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3911 | 		/* stop operation for this adapter */ | 
 | 3912 | 		debug_text_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 3913 | 				     "fsf_s_class_nsup"); | 
 | 3914 | 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3915 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3916 | 		break; | 
 | 3917 |  | 
 | 3918 | 	case FSF_FCPLUN_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3919 | 		ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on " | 
 | 3920 | 				"adapter %s does not have correct unit " | 
 | 3921 | 				"handle 0x%x\n", | 
 | 3922 | 				unit->fcp_lun, | 
 | 3923 | 				unit->port->wwpn, | 
 | 3924 | 				zfcp_get_busid_by_unit(unit), | 
 | 3925 | 				unit->handle); | 
 | 3926 | 		ZFCP_LOG_DEBUG("status qualifier:\n"); | 
 | 3927 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 3928 | 			      (char *) &header->fsf_status_qual, | 
 | 3929 | 			      sizeof (union fsf_status_qual)); | 
 | 3930 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 3931 | 				 "fsf_s_fcp_lun_nv"); | 
 | 3932 | 		zfcp_erp_port_reopen(unit->port, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3933 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3934 | 		break; | 
 | 3935 |  | 
 | 3936 | 	case FSF_ACCESS_DENIED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3937 | 		ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to " | 
 | 3938 | 				"unit 0x%016Lx on port 0x%016Lx on " | 
 | 3939 | 				"adapter %s\n",	unit->fcp_lun, unit->port->wwpn, | 
 | 3940 | 				zfcp_get_busid_by_unit(unit)); | 
 | 3941 | 		for (counter = 0; counter < 2; counter++) { | 
 | 3942 | 			subtable = header->fsf_status_qual.halfword[counter * 2]; | 
 | 3943 | 			rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | 
 | 3944 | 			switch (subtable) { | 
 | 3945 | 			case FSF_SQ_CFDC_SUBTABLE_OS: | 
 | 3946 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | 
 | 3947 | 			case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | 
 | 3948 | 			case FSF_SQ_CFDC_SUBTABLE_LUN: | 
 | 3949 | 				ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | 
 | 3950 | 					zfcp_act_subtable_type[subtable], rule); | 
 | 3951 | 				break; | 
 | 3952 | 			} | 
 | 3953 | 		} | 
 | 3954 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); | 
 | 3955 | 		zfcp_erp_unit_access_denied(unit); | 
 | 3956 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3957 | 		break; | 
 | 3958 |  | 
 | 3959 | 	case FSF_DIRECTION_INDICATOR_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3960 | 		ZFCP_LOG_INFO("bug: Invalid data direction given for unit " | 
 | 3961 | 			      "0x%016Lx on port 0x%016Lx on adapter %s " | 
 | 3962 | 			      "(debug info %d)\n", | 
 | 3963 | 			      unit->fcp_lun, | 
 | 3964 | 			      unit->port->wwpn, | 
 | 3965 | 			      zfcp_get_busid_by_unit(unit), | 
 | 3966 | 			      fsf_req->qtcb->bottom.io.data_direction); | 
 | 3967 | 		/* stop operation for this adapter */ | 
 | 3968 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 3969 | 				 "fsf_s_dir_ind_nv"); | 
 | 3970 | 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3971 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3972 | 		break; | 
 | 3973 |  | 
 | 3974 | 	case FSF_CMND_LENGTH_NOT_VALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3975 | 		ZFCP_LOG_NORMAL | 
 | 3976 | 		    ("bug: An invalid control-data-block length field " | 
 | 3977 | 		     "was found in a command for unit 0x%016Lx on port " | 
 | 3978 | 		     "0x%016Lx on adapter %s " "(debug info %d)\n", | 
 | 3979 | 		     unit->fcp_lun, unit->port->wwpn, | 
 | 3980 | 		     zfcp_get_busid_by_unit(unit), | 
 | 3981 | 		     fsf_req->qtcb->bottom.io.fcp_cmnd_length); | 
 | 3982 | 		/* stop operation for this adapter */ | 
 | 3983 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 3984 | 				 "fsf_s_cmd_len_nv"); | 
 | 3985 | 		zfcp_erp_adapter_shutdown(unit->port->adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3986 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 3987 | 		break; | 
 | 3988 |  | 
 | 3989 | 	case FSF_PORT_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3990 | 		ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 
 | 3991 | 			       "needs to be reopened\n", | 
 | 3992 | 			       unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 
 | 3993 | 		debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_pboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 3994 | 		zfcp_erp_port_boxed(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3995 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | 
 | 3996 | 			ZFCP_STATUS_FSFREQ_RETRY; | 
 | 3997 | 		break; | 
 | 3998 |  | 
 | 3999 | 	case FSF_LUN_BOXED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4000 | 		ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, " | 
 | 4001 | 				"wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | 
 | 4002 | 				zfcp_get_busid_by_unit(unit), | 
 | 4003 | 				unit->port->wwpn, unit->fcp_lun); | 
 | 4004 | 		debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed"); | 
| Andreas Herrmann | d736a27 | 2005-06-13 13:23:57 +0200 | [diff] [blame] | 4005 | 		zfcp_erp_unit_boxed(unit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4006 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | 
 | 4007 | 			| ZFCP_STATUS_FSFREQ_RETRY; | 
 | 4008 | 		break; | 
 | 4009 |  | 
 | 4010 | 	case FSF_ADAPTER_STATUS_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4011 | 		switch (header->fsf_status_qual.word[0]) { | 
 | 4012 | 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4013 | 			/* re-establish link to port */ | 
 | 4014 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 4015 | 					 "fsf_sq_ltest"); | 
| Andreas Herrmann | 65a8d4e | 2005-06-13 13:16:27 +0200 | [diff] [blame] | 4016 |  			zfcp_test_link(unit->port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4017 | 			break; | 
 | 4018 | 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4019 | 			/* FIXME(hw) need proper specs for proper action */ | 
 | 4020 | 			/* let scsi stack deal with retries and escalation */ | 
 | 4021 | 			debug_text_event(fsf_req->adapter->erp_dbf, 1, | 
 | 4022 | 					 "fsf_sq_ulp"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4023 | 			break; | 
 | 4024 | 		default: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4025 | 			ZFCP_LOG_NORMAL | 
| Andreas Herrmann | 516a420 | 2005-06-13 13:17:44 +0200 | [diff] [blame] | 4026 |  			    ("Unknown status qualifier 0x%x arrived.\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4027 | 			     header->fsf_status_qual.word[0]); | 
 | 4028 | 			debug_text_event(fsf_req->adapter->erp_dbf, 0, | 
 | 4029 | 					 "fsf_sq_inval:"); | 
 | 4030 | 			debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 4031 | 					&header->fsf_status_qual.word[0], | 
 | 4032 | 					sizeof(u32)); | 
 | 4033 | 			break; | 
 | 4034 | 		} | 
| Andreas Herrmann | 516a420 | 2005-06-13 13:17:44 +0200 | [diff] [blame] | 4035 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4036 | 		break; | 
 | 4037 |  | 
 | 4038 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4039 | 		break; | 
 | 4040 |  | 
 | 4041 | 	case FSF_FCP_RSP_AVAILABLE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4042 | 		break; | 
 | 4043 |  | 
 | 4044 | 	default: | 
 | 4045 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); | 
 | 4046 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 4047 | 				&header->fsf_status, sizeof(u32)); | 
 | 4048 | 		break; | 
 | 4049 | 	} | 
 | 4050 |  | 
 | 4051 |  skip_fsfstatus: | 
 | 4052 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) { | 
 | 4053 | 		retval = | 
 | 4054 | 		    zfcp_fsf_send_fcp_command_task_management_handler(fsf_req); | 
 | 4055 | 	} else { | 
 | 4056 | 		retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req); | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 4057 | 		fsf_req->unit = NULL; | 
 | 4058 | 		zfcp_unit_put(unit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4059 | 	} | 
 | 4060 | 	return retval; | 
 | 4061 | } | 
 | 4062 |  | 
 | 4063 | /* | 
 | 4064 |  * function:    zfcp_fsf_send_fcp_command_task_handler | 
 | 4065 |  * | 
 | 4066 |  * purpose:	evaluates FCP_RSP IU | 
 | 4067 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 4068 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4069 |  */ | 
 | 4070 | static int | 
 | 4071 | zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) | 
 | 4072 | { | 
 | 4073 | 	int retval = 0; | 
 | 4074 | 	struct scsi_cmnd *scpnt; | 
 | 4075 | 	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 
 | 4076 | 	    &(fsf_req->qtcb->bottom.io.fcp_rsp); | 
 | 4077 | 	struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *) | 
 | 4078 | 	    &(fsf_req->qtcb->bottom.io.fcp_cmnd); | 
 | 4079 | 	u32 sns_len; | 
 | 4080 | 	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 
 | 4081 | 	unsigned long flags; | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 4082 | 	struct zfcp_unit *unit = fsf_req->unit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4083 |  | 
 | 4084 | 	read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 4085 | 	scpnt = (struct scsi_cmnd *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4086 | 	if (unlikely(!scpnt)) { | 
 | 4087 | 		ZFCP_LOG_DEBUG | 
 | 4088 | 		    ("Command with fsf_req %p is not associated to " | 
 | 4089 | 		     "a scsi command anymore. Aborted?\n", fsf_req); | 
 | 4090 | 		goto out; | 
 | 4091 | 	} | 
 | 4092 | 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { | 
 | 4093 | 		/* FIXME: (design) mid-layer should handle DID_ABORT like | 
 | 4094 | 		 *        DID_SOFT_ERROR by retrying the request for devices | 
 | 4095 | 		 *        that allow retries. | 
 | 4096 | 		 */ | 
 | 4097 | 		ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n"); | 
 | 4098 | 		set_host_byte(&scpnt->result, DID_SOFT_ERROR); | 
 | 4099 | 		set_driver_byte(&scpnt->result, SUGGEST_RETRY); | 
 | 4100 | 		goto skip_fsfstatus; | 
 | 4101 | 	} | 
 | 4102 |  | 
 | 4103 | 	if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 
 | 4104 | 		ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); | 
 | 4105 | 		set_host_byte(&scpnt->result, DID_ERROR); | 
 | 4106 | 		goto skip_fsfstatus; | 
 | 4107 | 	} | 
 | 4108 |  | 
 | 4109 | 	/* set message byte of result in SCSI command */ | 
 | 4110 | 	scpnt->result |= COMMAND_COMPLETE << 8; | 
 | 4111 |  | 
 | 4112 | 	/* | 
 | 4113 | 	 * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte | 
 | 4114 | 	 * of result in SCSI command | 
 | 4115 | 	 */ | 
 | 4116 | 	scpnt->result |= fcp_rsp_iu->scsi_status; | 
 | 4117 | 	if (unlikely(fcp_rsp_iu->scsi_status)) { | 
 | 4118 | 		/* DEBUG */ | 
 | 4119 | 		ZFCP_LOG_DEBUG("status for SCSI Command:\n"); | 
 | 4120 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4121 | 			      scpnt->cmnd, scpnt->cmd_len); | 
 | 4122 | 		ZFCP_LOG_DEBUG("SCSI status code 0x%x\n", | 
 | 4123 | 				fcp_rsp_iu->scsi_status); | 
 | 4124 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4125 | 			      (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu)); | 
 | 4126 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4127 | 			      zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), | 
 | 4128 | 			      fcp_rsp_iu->fcp_sns_len); | 
 | 4129 | 	} | 
 | 4130 |  | 
 | 4131 | 	/* check FCP_RSP_INFO */ | 
 | 4132 | 	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { | 
 | 4133 | 		ZFCP_LOG_DEBUG("rsp_len is valid\n"); | 
 | 4134 | 		switch (fcp_rsp_info[3]) { | 
 | 4135 | 		case RSP_CODE_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4136 | 			/* ok, continue */ | 
 | 4137 | 			ZFCP_LOG_TRACE("no failure or Task Management " | 
 | 4138 | 				       "Function complete\n"); | 
 | 4139 | 			set_host_byte(&scpnt->result, DID_OK); | 
 | 4140 | 			break; | 
 | 4141 | 		case RSP_CODE_LENGTH_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4142 | 			/* hardware bug */ | 
 | 4143 | 			ZFCP_LOG_NORMAL("bug: FCP response code indictates " | 
 | 4144 | 					"that the fibrechannel protocol data " | 
 | 4145 | 					"length differs from the burst length. " | 
 | 4146 | 					"The problem occured on unit 0x%016Lx " | 
 | 4147 | 					"on port 0x%016Lx on adapter %s", | 
 | 4148 | 					unit->fcp_lun, | 
 | 4149 | 					unit->port->wwpn, | 
 | 4150 | 					zfcp_get_busid_by_unit(unit)); | 
 | 4151 | 			/* dump SCSI CDB as prepared by zfcp */ | 
 | 4152 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4153 | 				      (char *) &fsf_req->qtcb-> | 
 | 4154 | 				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4155 | 			set_host_byte(&scpnt->result, DID_ERROR); | 
 | 4156 | 			goto skip_fsfstatus; | 
 | 4157 | 		case RSP_CODE_FIELD_INVALID: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4158 | 			/* driver or hardware bug */ | 
 | 4159 | 			ZFCP_LOG_NORMAL("bug: FCP response code indictates " | 
 | 4160 | 					"that the fibrechannel protocol data " | 
 | 4161 | 					"fields were incorrectly set up. " | 
 | 4162 | 					"The problem occured on the unit " | 
 | 4163 | 					"0x%016Lx on port 0x%016Lx on " | 
 | 4164 | 					"adapter %s", | 
 | 4165 | 					unit->fcp_lun, | 
 | 4166 | 					unit->port->wwpn, | 
 | 4167 | 					zfcp_get_busid_by_unit(unit)); | 
 | 4168 | 			/* dump SCSI CDB as prepared by zfcp */ | 
 | 4169 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4170 | 				      (char *) &fsf_req->qtcb-> | 
 | 4171 | 				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | 
 | 4172 | 			set_host_byte(&scpnt->result, DID_ERROR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4173 | 			goto skip_fsfstatus; | 
 | 4174 | 		case RSP_CODE_RO_MISMATCH: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4175 | 			/* hardware bug */ | 
 | 4176 | 			ZFCP_LOG_NORMAL("bug: The FCP response code indicates " | 
 | 4177 | 					"that conflicting  values for the " | 
 | 4178 | 					"fibrechannel payload offset from the " | 
 | 4179 | 					"header were found. " | 
 | 4180 | 					"The problem occured on unit 0x%016Lx " | 
 | 4181 | 					"on port 0x%016Lx on adapter %s.\n", | 
 | 4182 | 					unit->fcp_lun, | 
 | 4183 | 					unit->port->wwpn, | 
 | 4184 | 					zfcp_get_busid_by_unit(unit)); | 
 | 4185 | 			/* dump SCSI CDB as prepared by zfcp */ | 
 | 4186 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4187 | 				      (char *) &fsf_req->qtcb-> | 
 | 4188 | 				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4189 | 			set_host_byte(&scpnt->result, DID_ERROR); | 
 | 4190 | 			goto skip_fsfstatus; | 
 | 4191 | 		default: | 
 | 4192 | 			ZFCP_LOG_NORMAL("bug: An invalid FCP response " | 
 | 4193 | 					"code was detected for a command. " | 
 | 4194 | 					"The problem occured on the unit " | 
 | 4195 | 					"0x%016Lx on port 0x%016Lx on " | 
 | 4196 | 					"adapter %s (debug info 0x%x)\n", | 
 | 4197 | 					unit->fcp_lun, | 
 | 4198 | 					unit->port->wwpn, | 
 | 4199 | 					zfcp_get_busid_by_unit(unit), | 
 | 4200 | 					fcp_rsp_info[3]); | 
 | 4201 | 			/* dump SCSI CDB as prepared by zfcp */ | 
 | 4202 | 			ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 
 | 4203 | 				      (char *) &fsf_req->qtcb-> | 
 | 4204 | 				      bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4205 | 			set_host_byte(&scpnt->result, DID_ERROR); | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 4206 | 			goto skip_fsfstatus; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4207 | 		} | 
 | 4208 | 	} | 
 | 4209 |  | 
 | 4210 | 	/* check for sense data */ | 
 | 4211 | 	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { | 
 | 4212 | 		sns_len = FSF_FCP_RSP_SIZE - | 
 | 4213 | 		    sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; | 
 | 4214 | 		ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", | 
 | 4215 | 			       sns_len); | 
 | 4216 | 		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); | 
 | 4217 | 		ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n", | 
 | 4218 | 			       SCSI_SENSE_BUFFERSIZE); | 
 | 4219 | 		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); | 
 | 4220 | 		ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", | 
 | 4221 | 			       scpnt->result); | 
 | 4222 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | 
 | 4223 | 			      (void *) &scpnt->cmnd, scpnt->cmd_len); | 
 | 4224 |  | 
 | 4225 | 		ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", | 
 | 4226 | 			       fcp_rsp_iu->fcp_sns_len); | 
| FUJITA Tomonori | 9d058ec | 2008-01-27 12:41:50 +0900 | [diff] [blame] | 4227 | 		memcpy(scpnt->sense_buffer, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4228 | 		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); | 
 | 4229 | 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | 
| FUJITA Tomonori | 9d058ec | 2008-01-27 12:41:50 +0900 | [diff] [blame] | 4230 | 			      (void *)scpnt->sense_buffer, sns_len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4231 | 	} | 
 | 4232 |  | 
 | 4233 | 	/* check for overrun */ | 
 | 4234 | 	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) { | 
 | 4235 | 		ZFCP_LOG_INFO("A data overrun was detected for a command. " | 
 | 4236 | 			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | 
 | 4237 | 			      "The response data length is " | 
 | 4238 | 			      "%d, the original length was %d.\n", | 
 | 4239 | 			      unit->fcp_lun, | 
 | 4240 | 			      unit->port->wwpn, | 
 | 4241 | 			      zfcp_get_busid_by_unit(unit), | 
 | 4242 | 			      fcp_rsp_iu->fcp_resid, | 
 | 4243 | 			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | 
 | 4244 | 	} | 
 | 4245 |  | 
 | 4246 | 	/* check for underrun */ | 
 | 4247 | 	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { | 
 | 4248 | 		ZFCP_LOG_INFO("A data underrun was detected for a command. " | 
 | 4249 | 			      "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | 
 | 4250 | 			      "The response data length is " | 
 | 4251 | 			      "%d, the original length was %d.\n", | 
 | 4252 | 			      unit->fcp_lun, | 
 | 4253 | 			      unit->port->wwpn, | 
 | 4254 | 			      zfcp_get_busid_by_unit(unit), | 
 | 4255 | 			      fcp_rsp_iu->fcp_resid, | 
 | 4256 | 			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | 
 | 4257 |  | 
| FUJITA Tomonori | 7936a89 | 2007-07-29 16:46:28 +0900 | [diff] [blame] | 4258 | 		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); | 
 | 4259 | 		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < | 
 | 4260 | 		    scpnt->underflow) | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 4261 | 			set_host_byte(&scpnt->result, DID_ERROR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4262 | 	} | 
 | 4263 |  | 
 | 4264 |  skip_fsfstatus: | 
 | 4265 | 	ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); | 
 | 4266 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4267 | 	if (scpnt->result != 0) | 
| Maxim Shchetynin | ed829ad | 2006-02-11 01:42:58 +0100 | [diff] [blame] | 4268 | 		zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req); | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4269 | 	else if (scpnt->retries > 0) | 
| Maxim Shchetynin | ed829ad | 2006-02-11 01:42:58 +0100 | [diff] [blame] | 4270 | 		zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req); | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4271 | 	else | 
| Maxim Shchetynin | ed829ad | 2006-02-11 01:42:58 +0100 | [diff] [blame] | 4272 | 		zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4273 |  | 
 | 4274 | 	/* cleanup pointer (need this especially for abort) */ | 
 | 4275 | 	scpnt->host_scribble = NULL; | 
 | 4276 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4277 | 	/* always call back */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4278 | 	(scpnt->scsi_done) (scpnt); | 
 | 4279 |  | 
 | 4280 | 	/* | 
 | 4281 | 	 * We must hold this lock until scsi_done has been called. | 
 | 4282 | 	 * Otherwise we may call scsi_done after abort regarding this | 
 | 4283 | 	 * command has completed. | 
 | 4284 | 	 * Note: scsi_done must not block! | 
 | 4285 | 	 */ | 
 | 4286 |  out: | 
 | 4287 | 	read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags); | 
 | 4288 | 	return retval; | 
 | 4289 | } | 
 | 4290 |  | 
 | 4291 | /* | 
 | 4292 |  * function:    zfcp_fsf_send_fcp_command_task_management_handler | 
 | 4293 |  * | 
 | 4294 |  * purpose:	evaluates FCP_RSP IU | 
 | 4295 |  * | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 4296 |  * returns: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4297 |  */ | 
 | 4298 | static int | 
 | 4299 | zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) | 
 | 4300 | { | 
 | 4301 | 	int retval = 0; | 
 | 4302 | 	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 
 | 4303 | 	    &(fsf_req->qtcb->bottom.io.fcp_rsp); | 
 | 4304 | 	char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 
| Andreas Herrmann | 059c97d | 2005-09-13 21:47:52 +0200 | [diff] [blame] | 4305 | 	struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4306 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4307 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 4308 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | 
 | 4309 | 		goto skip_fsfstatus; | 
 | 4310 | 	} | 
 | 4311 |  | 
 | 4312 | 	/* check FCP_RSP_INFO */ | 
 | 4313 | 	switch (fcp_rsp_info[3]) { | 
 | 4314 | 	case RSP_CODE_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4315 | 		/* ok, continue */ | 
 | 4316 | 		ZFCP_LOG_DEBUG("no failure or Task Management " | 
 | 4317 | 			       "Function complete\n"); | 
 | 4318 | 		break; | 
 | 4319 | 	case RSP_CODE_TASKMAN_UNSUPP: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4320 | 		ZFCP_LOG_NORMAL("bug: A reuested task management function " | 
 | 4321 | 				"is not supported on the target device " | 
 | 4322 | 				"unit 0x%016Lx, port 0x%016Lx, adapter %s\n ", | 
 | 4323 | 				unit->fcp_lun, | 
 | 4324 | 				unit->port->wwpn, | 
 | 4325 | 				zfcp_get_busid_by_unit(unit)); | 
 | 4326 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP; | 
 | 4327 | 		break; | 
 | 4328 | 	case RSP_CODE_TASKMAN_FAILED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4329 | 		ZFCP_LOG_NORMAL("bug: A reuested task management function " | 
 | 4330 | 				"failed to complete successfully. " | 
 | 4331 | 				"unit 0x%016Lx, port 0x%016Lx, adapter %s.\n", | 
 | 4332 | 				unit->fcp_lun, | 
 | 4333 | 				unit->port->wwpn, | 
 | 4334 | 				zfcp_get_busid_by_unit(unit)); | 
 | 4335 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | 
 | 4336 | 		break; | 
 | 4337 | 	default: | 
 | 4338 | 		ZFCP_LOG_NORMAL("bug: An invalid FCP response " | 
 | 4339 | 				"code was detected for a command. " | 
 | 4340 | 				"unit 0x%016Lx, port 0x%016Lx, adapter %s " | 
 | 4341 | 				"(debug info 0x%x)\n", | 
 | 4342 | 				unit->fcp_lun, | 
 | 4343 | 				unit->port->wwpn, | 
 | 4344 | 				zfcp_get_busid_by_unit(unit), | 
 | 4345 | 				fcp_rsp_info[3]); | 
 | 4346 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | 
 | 4347 | 	} | 
 | 4348 |  | 
 | 4349 |       skip_fsfstatus: | 
 | 4350 | 	return retval; | 
 | 4351 | } | 
 | 4352 |  | 
 | 4353 |  | 
 | 4354 | /* | 
 | 4355 |  * function:    zfcp_fsf_control_file | 
 | 4356 |  * | 
 | 4357 |  * purpose:     Initiator of the control file upload/download FSF requests | 
 | 4358 |  * | 
 | 4359 |  * returns:     0           - FSF request is successfuly created and queued | 
 | 4360 |  *              -EOPNOTSUPP - The FCP adapter does not have Control File support | 
 | 4361 |  *              -EINVAL     - Invalid direction specified | 
 | 4362 |  *              -ENOMEM     - Insufficient memory | 
 | 4363 |  *              -EPERM      - Cannot create FSF request or place it in QDIO queue | 
 | 4364 |  */ | 
 | 4365 | int | 
 | 4366 | zfcp_fsf_control_file(struct zfcp_adapter *adapter, | 
 | 4367 |                       struct zfcp_fsf_req **fsf_req_ptr, | 
 | 4368 |                       u32 fsf_command, | 
 | 4369 |                       u32 option, | 
 | 4370 |                       struct zfcp_sg_list *sg_list) | 
 | 4371 | { | 
 | 4372 | 	struct zfcp_fsf_req *fsf_req; | 
 | 4373 | 	struct fsf_qtcb_bottom_support *bottom; | 
 | 4374 | 	volatile struct qdio_buffer_element *sbale; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4375 | 	unsigned long lock_flags; | 
 | 4376 | 	int req_flags = 0; | 
 | 4377 | 	int direction; | 
 | 4378 | 	int retval = 0; | 
 | 4379 |  | 
| Maxim Shchetynin | aef4a98 | 2005-09-13 21:51:16 +0200 | [diff] [blame] | 4380 | 	if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4381 | 		ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", | 
 | 4382 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 4383 | 		retval = -EOPNOTSUPP; | 
 | 4384 | 		goto out; | 
 | 4385 | 	} | 
 | 4386 |  | 
 | 4387 | 	switch (fsf_command) { | 
 | 4388 |  | 
 | 4389 | 	case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | 
 | 4390 | 		direction = SBAL_FLAGS0_TYPE_WRITE; | 
 | 4391 | 		if ((option != FSF_CFDC_OPTION_FULL_ACCESS) && | 
 | 4392 | 		    (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS)) | 
 | 4393 | 			req_flags = ZFCP_WAIT_FOR_SBAL; | 
 | 4394 | 		break; | 
 | 4395 |  | 
 | 4396 | 	case FSF_QTCB_UPLOAD_CONTROL_FILE: | 
 | 4397 | 		direction = SBAL_FLAGS0_TYPE_READ; | 
 | 4398 | 		break; | 
 | 4399 |  | 
 | 4400 | 	default: | 
 | 4401 | 		ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); | 
 | 4402 | 		retval = -EINVAL; | 
 | 4403 | 		goto out; | 
 | 4404 | 	} | 
 | 4405 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4406 | 	retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, | 
 | 4407 | 				     NULL, &lock_flags, &fsf_req); | 
 | 4408 | 	if (retval < 0) { | 
 | 4409 | 		ZFCP_LOG_INFO("error: Could not create FSF request for the " | 
 | 4410 | 			      "adapter %s\n", | 
 | 4411 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4412 | 		retval = -EPERM; | 
 | 4413 | 		goto unlock_queue_lock; | 
 | 4414 | 	} | 
 | 4415 |  | 
 | 4416 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 4417 | 	sbale[0].flags |= direction; | 
 | 4418 |  | 
 | 4419 | 	bottom = &fsf_req->qtcb->bottom.support; | 
 | 4420 | 	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; | 
 | 4421 | 	bottom->option = option; | 
 | 4422 |  | 
 | 4423 | 	if (sg_list->count > 0) { | 
 | 4424 | 		int bytes; | 
 | 4425 |  | 
 | 4426 | 		bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, | 
 | 4427 | 						sg_list->sg, sg_list->count, | 
 | 4428 | 						ZFCP_MAX_SBALS_PER_REQ); | 
 | 4429 |                 if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) { | 
 | 4430 | 			ZFCP_LOG_INFO( | 
 | 4431 | 				"error: Could not create sufficient number of " | 
 | 4432 | 				"SBALS for an FSF request to the adapter %s\n", | 
 | 4433 | 				zfcp_get_busid_by_adapter(adapter)); | 
 | 4434 | 			retval = -ENOMEM; | 
 | 4435 | 			goto free_fsf_req; | 
 | 4436 | 		} | 
 | 4437 | 	} else | 
 | 4438 | 		sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 
 | 4439 |  | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 4440 | 	zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 
 | 4441 | 	retval = zfcp_fsf_req_send(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4442 | 	if (retval < 0) { | 
 | 4443 | 		ZFCP_LOG_INFO("initiation of cfdc up/download failed" | 
 | 4444 | 			      "(adapter %s)\n", | 
 | 4445 | 			      zfcp_get_busid_by_adapter(adapter)); | 
 | 4446 | 		retval = -EPERM; | 
 | 4447 | 		goto free_fsf_req; | 
 | 4448 | 	} | 
 | 4449 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
 | 4450 |  | 
 | 4451 | 	ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " | 
 | 4452 | 			"adapter %s\n", | 
 | 4453 | 			fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? | 
 | 4454 | 			"download" : "upload", | 
 | 4455 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4456 |  | 
 | 4457 | 	wait_event(fsf_req->completion_wq, | 
 | 4458 | 	           fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 
 | 4459 |  | 
 | 4460 | 	*fsf_req_ptr = fsf_req; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 4461 | 	goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4462 |  | 
 | 4463 |  free_fsf_req: | 
 | 4464 | 	zfcp_fsf_req_free(fsf_req); | 
 | 4465 |  unlock_queue_lock: | 
 | 4466 | 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4467 |  out: | 
 | 4468 | 	return retval; | 
 | 4469 | } | 
 | 4470 |  | 
 | 4471 |  | 
 | 4472 | /* | 
 | 4473 |  * function:    zfcp_fsf_control_file_handler | 
 | 4474 |  * | 
 | 4475 |  * purpose:     Handler of the control file upload/download FSF requests | 
 | 4476 |  * | 
 | 4477 |  * returns:     0       - FSF request successfuly processed | 
 | 4478 |  *              -EAGAIN - Operation has to be repeated because of a temporary problem | 
 | 4479 |  *              -EACCES - There is no permission to execute an operation | 
 | 4480 |  *              -EPERM  - The control file is not in a right format | 
 | 4481 |  *              -EIO    - There is a problem with the FCP adapter | 
 | 4482 |  *              -EINVAL - Invalid operation | 
 | 4483 |  *              -EFAULT - User space memory I/O operation fault | 
 | 4484 |  */ | 
 | 4485 | static int | 
 | 4486 | zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) | 
 | 4487 | { | 
 | 4488 | 	struct zfcp_adapter *adapter = fsf_req->adapter; | 
 | 4489 | 	struct fsf_qtcb_header *header = &fsf_req->qtcb->header; | 
 | 4490 | 	struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support; | 
 | 4491 | 	int retval = 0; | 
 | 4492 |  | 
 | 4493 | 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 
 | 4494 | 		retval = -EINVAL; | 
 | 4495 | 		goto skip_fsfstatus; | 
 | 4496 | 	} | 
 | 4497 |  | 
 | 4498 | 	switch (header->fsf_status) { | 
 | 4499 |  | 
 | 4500 | 	case FSF_GOOD: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4501 | 		ZFCP_LOG_NORMAL( | 
 | 4502 | 			"The FSF request has been successfully completed " | 
 | 4503 | 			"on the adapter %s\n", | 
 | 4504 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4505 | 		break; | 
 | 4506 |  | 
 | 4507 | 	case FSF_OPERATION_PARTIALLY_SUCCESSFUL: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4508 | 		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) { | 
 | 4509 | 			switch (header->fsf_status_qual.word[0]) { | 
 | 4510 |  | 
 | 6f71d9b | 2005-04-10 23:04:28 -0500 | [diff] [blame] | 4511 | 			case FSF_SQ_CFDC_HARDENED_ON_SE: | 
 | 4512 | 				ZFCP_LOG_NORMAL( | 
 | 4513 | 					"CFDC on the adapter %s has being " | 
 | 4514 | 					"hardened on primary and secondary SE\n", | 
 | 4515 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 4516 | 				break; | 
 | 4517 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4518 | 			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE: | 
 | 4519 | 				ZFCP_LOG_NORMAL( | 
 | 4520 | 					"CFDC of the adapter %s could not " | 
 | 4521 | 					"be saved on the SE\n", | 
 | 4522 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 4523 | 				break; | 
 | 4524 |  | 
 | 4525 | 			case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2: | 
 | 4526 | 				ZFCP_LOG_NORMAL( | 
 | 4527 | 					"CFDC of the adapter %s could not " | 
 | 4528 | 					"be copied to the secondary SE\n", | 
 | 4529 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 4530 | 				break; | 
 | 4531 |  | 
 | 4532 | 			default: | 
 | 4533 | 				ZFCP_LOG_NORMAL( | 
 | 4534 | 					"CFDC could not be hardened " | 
 | 4535 | 					"on the adapter %s\n", | 
 | 4536 | 					zfcp_get_busid_by_adapter(adapter)); | 
 | 4537 | 			} | 
 | 4538 | 		} | 
 | 4539 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4540 | 		retval = -EAGAIN; | 
 | 4541 | 		break; | 
 | 4542 |  | 
 | 4543 | 	case FSF_AUTHORIZATION_FAILURE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4544 | 		ZFCP_LOG_NORMAL( | 
 | 4545 | 			"Adapter %s does not accept privileged commands\n", | 
 | 4546 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4547 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4548 | 		retval = -EACCES; | 
 | 4549 | 		break; | 
 | 4550 |  | 
 | 4551 | 	case FSF_CFDC_ERROR_DETECTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4552 | 		ZFCP_LOG_NORMAL( | 
 | 4553 | 			"Error at position %d in the CFDC, " | 
 | 4554 | 			"CFDC is discarded by the adapter %s\n", | 
 | 4555 | 			header->fsf_status_qual.word[0], | 
 | 4556 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4557 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4558 | 		retval = -EPERM; | 
 | 4559 | 		break; | 
 | 4560 |  | 
 | 4561 | 	case FSF_CONTROL_FILE_UPDATE_ERROR: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4562 | 		ZFCP_LOG_NORMAL( | 
 | 4563 | 			"Adapter %s cannot harden the control file, " | 
 | 4564 | 			"file is discarded\n", | 
 | 4565 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4566 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4567 | 		retval = -EIO; | 
 | 4568 | 		break; | 
 | 4569 |  | 
 | 4570 | 	case FSF_CONTROL_FILE_TOO_LARGE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4571 | 		ZFCP_LOG_NORMAL( | 
 | 4572 | 			"Control file is too large, file is discarded " | 
 | 4573 | 			"by the adapter %s\n", | 
 | 4574 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4575 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4576 | 		retval = -EIO; | 
 | 4577 | 		break; | 
 | 4578 |  | 
 | 4579 | 	case FSF_ACCESS_CONFLICT_DETECTED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4580 | 		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 
 | 4581 | 			ZFCP_LOG_NORMAL( | 
 | 4582 | 				"CFDC has been discarded by the adapter %s, " | 
 | 4583 | 				"because activation would impact " | 
 | 4584 | 				"%d active connection(s)\n", | 
 | 4585 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 4586 | 				header->fsf_status_qual.word[0]); | 
 | 4587 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4588 | 		retval = -EIO; | 
 | 4589 | 		break; | 
 | 4590 |  | 
 | 4591 | 	case FSF_CONFLICTS_OVERRULED: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4592 | 		if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 
 | 4593 | 			ZFCP_LOG_NORMAL( | 
 | 4594 | 				"CFDC has been activated on the adapter %s, " | 
 | 4595 | 				"but activation has impacted " | 
 | 4596 | 				"%d active connection(s)\n", | 
 | 4597 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 4598 | 				header->fsf_status_qual.word[0]); | 
 | 4599 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4600 | 		retval = -EIO; | 
 | 4601 | 		break; | 
 | 4602 |  | 
 | 4603 | 	case FSF_UNKNOWN_OP_SUBTYPE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4604 | 		ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " | 
 | 4605 | 				"op_subtype=0x%x)\n", | 
 | 4606 | 				zfcp_get_busid_by_adapter(adapter), | 
 | 4607 | 				bottom->operation_subtype); | 
 | 4608 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4609 | 		retval = -EINVAL; | 
 | 4610 | 		break; | 
 | 4611 |  | 
 | 4612 | 	case FSF_INVALID_COMMAND_OPTION: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4613 | 		ZFCP_LOG_NORMAL( | 
 | 4614 | 			"Invalid option 0x%x has been specified " | 
 | 4615 | 			"in QTCB bottom sent to the adapter %s\n", | 
 | 4616 | 			bottom->option, | 
 | 4617 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4618 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4619 | 		retval = -EINVAL; | 
 | 4620 | 		break; | 
 | 4621 |  | 
 | 4622 | 	default: | 
 | 4623 | 		ZFCP_LOG_NORMAL( | 
 | 4624 | 			"bug: An unknown/unexpected FSF status 0x%08x " | 
 | 4625 | 			"was presented on the adapter %s\n", | 
 | 4626 | 			header->fsf_status, | 
 | 4627 | 			zfcp_get_busid_by_adapter(adapter)); | 
 | 4628 | 		debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval"); | 
 | 4629 | 		debug_exception(fsf_req->adapter->erp_dbf, 0, | 
 | 4630 | 			&header->fsf_status_qual.word[0], sizeof(u32)); | 
 | 4631 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 
 | 4632 | 		retval = -EINVAL; | 
 | 4633 | 		break; | 
 | 4634 | 	} | 
 | 4635 |  | 
 | 4636 | skip_fsfstatus: | 
 | 4637 | 	return retval; | 
 | 4638 | } | 
 | 4639 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4640 | static inline int | 
 | 4641 | zfcp_fsf_req_sbal_check(unsigned long *flags, | 
 | 4642 | 			struct zfcp_qdio_queue *queue, int needed) | 
 | 4643 | { | 
 | 4644 | 	write_lock_irqsave(&queue->queue_lock, *flags); | 
 | 4645 | 	if (likely(atomic_read(&queue->free_count) >= needed)) | 
 | 4646 | 		return 1; | 
 | 4647 | 	write_unlock_irqrestore(&queue->queue_lock, *flags); | 
 | 4648 | 	return 0; | 
 | 4649 | } | 
 | 4650 |  | 
 | 4651 | /* | 
 | 4652 |  * set qtcb pointer in fsf_req and initialize QTCB | 
 | 4653 |  */ | 
| Heiko Carstens | 4d284ca | 2007-02-05 21:18:53 +0100 | [diff] [blame] | 4654 | static void | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4655 | zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4656 | { | 
 | 4657 | 	if (likely(fsf_req->qtcb != NULL)) { | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4658 | 		fsf_req->qtcb->prefix.req_seq_no = | 
 | 4659 | 			fsf_req->adapter->fsf_req_seq_no; | 
 | 4660 | 		fsf_req->qtcb->prefix.req_id = fsf_req->req_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4661 | 		fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4662 | 		fsf_req->qtcb->prefix.qtcb_type = | 
 | 4663 | 			fsf_qtcb_type[fsf_req->fsf_command]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4664 | 		fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4665 | 		fsf_req->qtcb->header.req_handle = fsf_req->req_id; | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4666 | 		fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4667 | 	} | 
 | 4668 | } | 
 | 4669 |  | 
 | 4670 | /** | 
 | 4671 |  * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue | 
 | 4672 |  * @adapter: adapter for which request queue is examined | 
 | 4673 |  * @req_flags: flags indicating whether to wait for needed SBAL or not | 
 | 4674 |  * @lock_flags: lock_flags if queue_lock is taken | 
 | 4675 |  * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS | 
 | 4676 |  * Locks: lock adapter->request_queue->queue_lock on success | 
 | 4677 |  */ | 
 | 4678 | static int | 
 | 4679 | zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, | 
 | 4680 | 		      unsigned long *lock_flags) | 
 | 4681 | { | 
 | 4682 |         long ret; | 
 | 4683 |         struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | 
 | 4684 |  | 
 | 4685 |         if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { | 
 | 4686 |                 ret = wait_event_interruptible_timeout(adapter->request_wq, | 
 | 4687 | 			zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1), | 
 | 4688 | 						       ZFCP_SBAL_TIMEOUT); | 
 | 4689 | 		if (ret < 0) | 
 | 4690 | 			return ret; | 
 | 4691 | 		if (!ret) | 
 | 4692 | 			return -EIO; | 
 | 4693 |         } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) | 
 | 4694 |                 return -EIO; | 
 | 4695 |  | 
 | 4696 |         return 0; | 
 | 4697 | } | 
 | 4698 |  | 
 | 4699 | /* | 
 | 4700 |  * function:    zfcp_fsf_req_create | 
 | 4701 |  * | 
 | 4702 |  * purpose:	create an FSF request at the specified adapter and | 
 | 4703 |  *		setup common fields | 
 | 4704 |  * | 
 | 4705 |  * returns:	-ENOMEM if there was insufficient memory for a request | 
 | 4706 |  *              -EIO if no qdio buffers could be allocate to the request | 
 | 4707 |  *              -EINVAL/-EPERM on bug conditions in req_dequeue | 
 | 4708 |  *              0 in success | 
 | 4709 |  * | 
 | 4710 |  * note:        The created request is returned by reference. | 
 | 4711 |  * | 
 | 4712 |  * locks:	lock of concerned request queue must not be held, | 
 | 4713 |  *		but is held on completion (write, irqsave) | 
 | 4714 |  */ | 
 | 4715 | int | 
 | 4716 | zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, | 
 | 4717 | 		    mempool_t *pool, unsigned long *lock_flags, | 
 | 4718 | 		    struct zfcp_fsf_req **fsf_req_p) | 
 | 4719 | { | 
 | 4720 | 	volatile struct qdio_buffer_element *sbale; | 
 | 4721 | 	struct zfcp_fsf_req *fsf_req = NULL; | 
 | 4722 | 	int ret = 0; | 
 | 4723 | 	struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | 
 | 4724 |  | 
 | 4725 | 	/* allocate new FSF request */ | 
 | 4726 | 	fsf_req = zfcp_fsf_req_alloc(pool, req_flags); | 
 | 4727 | 	if (unlikely(NULL == fsf_req)) { | 
| Joe Perches | ceb3dfb | 2008-01-26 14:11:10 +0100 | [diff] [blame] | 4728 | 		ZFCP_LOG_DEBUG("error: Could not put an FSF request into " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4729 | 			       "the outbound (send) queue.\n"); | 
 | 4730 | 		ret = -ENOMEM; | 
 | 4731 | 		goto failed_fsf_req; | 
 | 4732 | 	} | 
 | 4733 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4734 | 	fsf_req->adapter = adapter; | 
 | 4735 | 	fsf_req->fsf_command = fsf_cmd; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4736 | 	INIT_LIST_HEAD(&fsf_req->list); | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 4737 | 	init_timer(&fsf_req->timer); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4738 |  | 
| Swen Schillig | 41fa2ad | 2007-09-07 09:15:31 +0200 | [diff] [blame] | 4739 | 	/* initialize waitqueue which may be used to wait on | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4740 | 	   this request completion */ | 
 | 4741 | 	init_waitqueue_head(&fsf_req->completion_wq); | 
 | 4742 |  | 
 | 4743 |         ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags); | 
| Christof Schmitt | 801e0ce | 2007-05-08 11:15:48 +0200 | [diff] [blame] | 4744 |         if (ret < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4745 |                 goto failed_sbals; | 
| Christof Schmitt | 801e0ce | 2007-05-08 11:15:48 +0200 | [diff] [blame] | 4746 |  | 
 | 4747 | 	/* this is serialized (we are holding req_queue-lock of adapter) */ | 
 | 4748 | 	if (adapter->req_no == 0) | 
 | 4749 | 		adapter->req_no++; | 
 | 4750 | 	fsf_req->req_id = adapter->req_no++; | 
 | 4751 |  | 
 | 4752 | 	zfcp_fsf_req_qtcb_init(fsf_req); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4753 |  | 
 | 4754 | 	/* | 
 | 4755 | 	 * We hold queue_lock here. Check if QDIOUP is set and let request fail | 
 | 4756 | 	 * if it is not set (see also *_open_qdio and *_close_qdio). | 
 | 4757 | 	 */ | 
 | 4758 |  | 
 | 4759 | 	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | 
 | 4760 | 		write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags); | 
 | 4761 | 		ret = -EIO; | 
 | 4762 | 		goto failed_sbals; | 
 | 4763 | 	} | 
 | 4764 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4765 | 	if (fsf_req->qtcb) { | 
 | 4766 | 		fsf_req->seq_no = adapter->fsf_req_seq_no; | 
 | 4767 | 		fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; | 
 | 4768 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4769 | 	fsf_req->sbal_number = 1; | 
 | 4770 | 	fsf_req->sbal_first = req_queue->free_index; | 
 | 4771 | 	fsf_req->sbal_curr = req_queue->free_index; | 
 | 4772 |         fsf_req->sbale_curr = 1; | 
 | 4773 |  | 
 | 4774 | 	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { | 
 | 4775 | 		fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; | 
 | 4776 | 	} | 
 | 4777 |  | 
 | 4778 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 
 | 4779 |  | 
 | 4780 | 	/* setup common SBALE fields */ | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4781 | 	sbale[0].addr = (void *) fsf_req->req_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4782 | 	sbale[0].flags |= SBAL_FLAGS0_COMMAND; | 
 | 4783 | 	if (likely(fsf_req->qtcb != NULL)) { | 
 | 4784 | 		sbale[1].addr = (void *) fsf_req->qtcb; | 
 | 4785 | 		sbale[1].length = sizeof(struct fsf_qtcb); | 
 | 4786 | 	} | 
 | 4787 |  | 
 | 4788 | 	ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n", | 
 | 4789 |                        fsf_req->sbal_number, fsf_req->sbal_first); | 
 | 4790 |  | 
 | 4791 | 	goto success; | 
 | 4792 |  | 
 | 4793 |  failed_sbals: | 
 | 4794 | /* dequeue new FSF request previously enqueued */ | 
 | 4795 | 	zfcp_fsf_req_free(fsf_req); | 
 | 4796 | 	fsf_req = NULL; | 
 | 4797 |  | 
 | 4798 |  failed_fsf_req: | 
 | 4799 | 	write_lock_irqsave(&req_queue->queue_lock, *lock_flags); | 
 | 4800 |  success: | 
 | 4801 | 	*fsf_req_p = fsf_req; | 
 | 4802 | 	return ret; | 
 | 4803 | } | 
 | 4804 |  | 
 | 4805 | /* | 
 | 4806 |  * function:    zfcp_fsf_req_send | 
 | 4807 |  * | 
 | 4808 |  * purpose:	start transfer of FSF request via QDIO | 
 | 4809 |  * | 
 | 4810 |  * returns:	0 - request transfer succesfully started | 
 | 4811 |  *		!0 - start of request transfer failed | 
 | 4812 |  */ | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 4813 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4814 | { | 
 | 4815 | 	struct zfcp_adapter *adapter; | 
 | 4816 | 	struct zfcp_qdio_queue *req_queue; | 
 | 4817 | 	volatile struct qdio_buffer_element *sbale; | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4818 | 	int inc_seq_no; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4819 | 	int new_distance_from_int; | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4820 | 	u64 dbg_tmp[2]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4821 | 	int retval = 0; | 
 | 4822 |  | 
 | 4823 | 	adapter = fsf_req->adapter; | 
 | 4824 | 	req_queue = &adapter->request_queue, | 
 | 4825 |  | 
 | 4826 |  | 
 | 4827 | 	/* FIXME(debug): remove it later */ | 
 | 4828 | 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0); | 
 | 4829 | 	ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags); | 
 | 4830 | 	ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n"); | 
 | 4831 | 	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, | 
 | 4832 | 		      sbale[1].length); | 
 | 4833 |  | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4834 | 	/* put allocated FSF request into hash table */ | 
 | 4835 | 	spin_lock(&adapter->req_list_lock); | 
 | 4836 | 	zfcp_reqlist_add(adapter, fsf_req); | 
 | 4837 | 	spin_unlock(&adapter->req_list_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4838 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4839 | 	inc_seq_no = (fsf_req->qtcb != NULL); | 
 | 4840 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4841 | 	ZFCP_LOG_TRACE("request queue of adapter %s: " | 
 | 4842 | 		       "next free SBAL is %i, %i free SBALs\n", | 
 | 4843 | 		       zfcp_get_busid_by_adapter(adapter), | 
 | 4844 | 		       req_queue->free_index, | 
 | 4845 | 		       atomic_read(&req_queue->free_count)); | 
 | 4846 |  | 
 | 4847 | 	ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, " | 
 | 4848 | 		       "index_in_queue=%i, count=%i, buffers=%p\n", | 
 | 4849 | 		       zfcp_get_busid_by_adapter(adapter), | 
 | 4850 | 		       QDIO_FLAG_SYNC_OUTPUT, | 
 | 4851 | 		       0, fsf_req->sbal_first, fsf_req->sbal_number, | 
 | 4852 | 		       &req_queue->buffer[fsf_req->sbal_first]); | 
 | 4853 |  | 
 | 4854 | 	/* | 
 | 4855 | 	 * adjust the number of free SBALs in request queue as well as | 
 | 4856 | 	 * position of first one | 
 | 4857 | 	 */ | 
 | 4858 | 	atomic_sub(fsf_req->sbal_number, &req_queue->free_count); | 
 | 4859 | 	ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count)); | 
 | 4860 | 	req_queue->free_index += fsf_req->sbal_number;	  /* increase */ | 
 | 4861 | 	req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q;  /* wrap if needed */ | 
 | 4862 | 	new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req); | 
 | 4863 |  | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4864 | 	fsf_req->issued = get_clock(); | 
 | 4865 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4866 | 	retval = do_QDIO(adapter->ccw_device, | 
 | 4867 | 			 QDIO_FLAG_SYNC_OUTPUT, | 
 | 4868 | 			 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); | 
 | 4869 |  | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4870 | 	dbg_tmp[0] = (unsigned long) sbale[0].addr; | 
 | 4871 | 	dbg_tmp[1] = (u64) retval; | 
 | 4872 | 	debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); | 
 | 4873 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4874 | 	if (unlikely(retval)) { | 
 | 4875 | 		/* Queues are down..... */ | 
 | 4876 | 		retval = -EIO; | 
| Andreas Herrmann | 2abbe86 | 2006-09-18 22:29:56 +0200 | [diff] [blame] | 4877 | 		del_timer(&fsf_req->timer); | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4878 | 		spin_lock(&adapter->req_list_lock); | 
| Heiko Carstens | ca2d02c | 2007-05-08 11:17:54 +0200 | [diff] [blame] | 4879 | 		zfcp_reqlist_remove(adapter, fsf_req); | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4880 | 		spin_unlock(&adapter->req_list_lock); | 
 | 4881 | 		/* undo changes in request queue made for this request */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4882 | 		zfcp_qdio_zero_sbals(req_queue->buffer, | 
 | 4883 | 				     fsf_req->sbal_first, fsf_req->sbal_number); | 
 | 4884 | 		atomic_add(fsf_req->sbal_number, &req_queue->free_count); | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4885 | 		req_queue->free_index -= fsf_req->sbal_number; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4886 | 		req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q; | 
 | 4887 | 		req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4888 | 		zfcp_erp_adapter_reopen(adapter, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4889 | 	} else { | 
 | 4890 | 		req_queue->distance_from_int = new_distance_from_int; | 
 | 4891 | 		/* | 
 | 4892 | 		 * increase FSF sequence counter - | 
 | 4893 | 		 * this must only be done for request successfully enqueued to | 
 | 4894 | 		 * QDIO this rejected requests may be cleaned up by calling | 
 | 4895 | 		 * routines  resulting in missing sequence counter values | 
 | 4896 | 		 * otherwise, | 
 | 4897 | 		 */ | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4898 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4899 | 		/* Don't increase for unsolicited status */ | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4900 | 		if (inc_seq_no) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4901 | 			adapter->fsf_req_seq_no++; | 
| Maxim Shchetynin | 8a36e45 | 2005-09-13 21:50:38 +0200 | [diff] [blame] | 4902 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4903 | 		/* count FSF requests pending */ | 
| Volker Sameske | fea9d6c | 2006-08-02 11:05:16 +0200 | [diff] [blame] | 4904 | 		atomic_inc(&adapter->reqs_active); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4905 | 	} | 
 | 4906 | 	return retval; | 
 | 4907 | } | 
 | 4908 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4909 | #undef ZFCP_LOG_AREA |