Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/impl/fctl.c
+++ new/usr/src/uts/common/io/fibre-channel/impl/fctl.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 27 */
28 28 /*
29 29 * Fibre channel Transport Library (fctl)
30 30 *
31 31 * Function naming conventions:
32 32 * Functions called from ULPs begin with fc_ulp_
33 33 * Functions called from FCAs begin with fc_fca_
34 34 * Internal functions begin with fctl_
35 35 *
36 36 * Fibre channel packet layout:
37 37 * +---------------------+<--------+
38 38 * | | |
39 39 * | ULP Packet private | |
40 40 * | | |
41 41 * +---------------------+ |
42 42 * | |---------+
43 43 * | struct fc_packet |---------+
44 44 * | | |
45 45 * +---------------------+<--------+
46 46 * | |
47 47 * | FCA Packet private |
48 48 * | |
49 49 * +---------------------+
50 50 *
51 51 * So you loved the ascii art ? It's strongly desirable to cache
52 52 * allocate the entire packet in one common place. So we define a set a
53 53 * of rules. In a contiguous block of memory, the top portion of the
54 54 * block points to ulp packet private area, next follows the fc_packet
55 55 * structure used extensively by all the consumers and what follows this
56 56 * is the FCA packet private. Note that given a packet structure, it is
57 57 * possible to get to the ULP and FCA Packet private fields using
58 58 * ulp_private and fca_private fields (which hold pointers) respectively.
59 59 *
60 60 * It should be noted with a grain of salt that ULP Packet private size
61 61 * varies between two different ULP types, So this poses a challenge to
62 62 * compute the correct size of the whole block on a per port basis. The
63 63 * transport layer doesn't have a problem in dealing with FCA packet
64 64 * private sizes as it is the sole manager of ports underneath. Since
65 65 * it's not a good idea to cache allocate different sizes of memory for
66 66 * different ULPs and have the ability to choose from one of these caches
67 67 * based on ULP type during every packet allocation, the transport some
68 68 * what wisely (?) hands off this job of cache allocation to the ULPs
69 69 * themselves.
70 70 *
71 71 * That means FCAs need to make their packet private size known to the
72 72 * transport to pass it up to the ULPs. This is done during
73 73 * fc_fca_attach(). And the transport passes this size up to ULPs during
74 74 * fc_ulp_port_attach() of each ULP.
75 75 *
76 76 * This leaves us with another possible question; How are packets
77 77 * allocated for ELS's started by the transport itself ? Well, the port
78 78 * driver during attach time, cache allocates on a per port basis to
79 79 * handle ELSs too.
80 80 */
81 81
82 82 #include <sys/note.h>
83 83 #include <sys/types.h>
84 84 #include <sys/varargs.h>
85 85 #include <sys/param.h>
86 86 #include <sys/errno.h>
87 87 #include <sys/uio.h>
88 88 #include <sys/buf.h>
89 89 #include <sys/modctl.h>
90 90 #include <sys/open.h>
91 91 #include <sys/kmem.h>
92 92 #include <sys/poll.h>
93 93 #include <sys/conf.h>
94 94 #include <sys/cmn_err.h>
95 95 #include <sys/stat.h>
96 96 #include <sys/ddi.h>
97 97 #include <sys/sunddi.h>
98 98 #include <sys/promif.h>
99 99 #include <sys/byteorder.h>
100 100 #include <sys/fibre-channel/fc.h>
101 101 #include <sys/fibre-channel/impl/fc_ulpif.h>
102 102 #include <sys/fibre-channel/impl/fc_fcaif.h>
103 103 #include <sys/fibre-channel/impl/fctl_private.h>
104 104 #include <sys/fibre-channel/impl/fc_portif.h>
105 105
106 106 /* These are referenced by fp.c! */
107 107 int did_table_size = D_ID_HASH_TABLE_SIZE;
108 108 int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
109 109
110 110 static fc_ulp_module_t *fctl_ulp_modules;
111 111 static fc_fca_port_t *fctl_fca_portlist;
112 112 static fc_ulp_list_t *fctl_ulp_list;
113 113
114 114 static char fctl_greeting[] =
115 115 "fctl: %s ULP same type (0x%x) as existing module.\n";
116 116
117 117 static char *fctl_undefined = "Undefined";
118 118
119 119 /*
120 120 * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
121 121 */
122 122
123 123 static krwlock_t fctl_ulp_lock;
124 124
125 125 /*
126 126 * The fctl_mod_ports_lock protects the mod_ports element in the
127 127 * fc_ulp_ports_t structure
128 128 */
129 129
130 130 static krwlock_t fctl_mod_ports_lock;
131 131
132 132 /*
133 133 * fctl_port_lock protects the linked list of local port structures
134 134 * (fctl_fca_portlist). When walking the list, this lock must be obtained
135 135 * prior to any local port locks.
136 136 */
137 137
138 138 static kmutex_t fctl_port_lock;
139 139 static kmutex_t fctl_ulp_list_mutex;
140 140
141 141 static fctl_nwwn_list_t *fctl_nwwn_hash_table;
142 142 static kmutex_t fctl_nwwn_hash_mutex;
143 143 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
144 144
145 145 #if !defined(lint)
146 146 _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
147 147 _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
148 148 _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
149 149 _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
150 150 ulp_ports::port_handle))
151 151 _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
152 152 _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
153 153 ulp_ports::port_dstate))
154 154 #endif /* lint */
155 155
156 156 #define FCTL_VERSION "20090729-1.70"
157 157 #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION
158 158
159 159 char *fctl_version = FCTL_NAME_VERSION;
160 160
161 161 extern struct mod_ops mod_miscops;
162 162
163 163 static struct modlmisc modlmisc = {
164 164 &mod_miscops, /* type of module */
165 165 FCTL_NAME_VERSION /* Module name */
166 166 };
167 167
168 168 static struct modlinkage modlinkage = {
169 169 MODREV_1, (void *)&modlmisc, NULL
170 170 };
171 171
172 172 static struct bus_ops fctl_fca_busops = {
173 173 BUSO_REV,
174 174 nullbusmap, /* bus_map */
175 175 NULL, /* bus_get_intrspec */
176 176 NULL, /* bus_add_intrspec */
177 177 NULL, /* bus_remove_intrspec */
178 178 i_ddi_map_fault, /* bus_map_fault */
179 179 NULL, /* bus_dma_map */
180 180 ddi_dma_allochdl, /* bus_dma_allochdl */
181 181 ddi_dma_freehdl, /* bus_dma_freehdl */
182 182 ddi_dma_bindhdl, /* bus_dma_bindhdl */
183 183 ddi_dma_unbindhdl, /* bus_unbindhdl */
184 184 ddi_dma_flush, /* bus_dma_flush */
185 185 ddi_dma_win, /* bus_dma_win */
186 186 ddi_dma_mctl, /* bus_dma_ctl */
187 187 fctl_fca_bus_ctl, /* bus_ctl */
188 188 ddi_bus_prop_op, /* bus_prop_op */
189 189 NULL, /* bus_get_eventcookie */
190 190 NULL, /* bus_add_eventcall */
191 191 NULL, /* bus_remove_event */
192 192 NULL, /* bus_post_event */
193 193 NULL, /* bus_intr_ctl */
194 194 NULL, /* bus_config */
195 195 NULL, /* bus_unconfig */
196 196 NULL, /* bus_fm_init */
197 197 NULL, /* bus_fm_fini */
198 198 NULL, /* bus_fm_access_enter */
199 199 NULL, /* bus_fm_access_exit */
200 200 NULL, /* bus_power */
201 201 NULL
202 202 };
203 203
204 204 struct kmem_cache *fctl_job_cache;
205 205
206 206 static fc_errmap_t fc_errlist [] = {
207 207 { FC_FAILURE, "Operation failed" },
208 208 { FC_SUCCESS, "Operation success" },
209 209 { FC_CAP_ERROR, "Capability error" },
210 210 { FC_CAP_FOUND, "Capability found" },
211 211 { FC_CAP_SETTABLE, "Capability settable" },
212 212 { FC_UNBOUND, "Port not bound" },
213 213 { FC_NOMEM, "No memory" },
214 214 { FC_BADPACKET, "Bad packet" },
215 215 { FC_OFFLINE, "Port offline" },
216 216 { FC_OLDPORT, "Old Port" },
217 217 { FC_NO_MAP, "No map available" },
218 218 { FC_TRANSPORT_ERROR, "Transport error" },
219 219 { FC_ELS_FREJECT, "ELS Frejected" },
220 220 { FC_ELS_PREJECT, "ELS PRejected" },
221 221 { FC_ELS_BAD, "Bad ELS request" },
222 222 { FC_ELS_MALFORMED, "Malformed ELS request" },
223 223 { FC_TOOMANY, "Too many commands" },
224 224 { FC_UB_BADTOKEN, "Bad Unsolicited buffer token" },
225 225 { FC_UB_ERROR, "Unsolicited buffer error" },
226 226 { FC_UB_BUSY, "Unsolicited buffer busy" },
227 227 { FC_BADULP, "Bad ULP" },
228 228 { FC_BADTYPE, "Bad Type" },
229 229 { FC_UNCLAIMED, "Not Claimed" },
230 230 { FC_ULP_SAMEMODULE, "Same ULP Module" },
231 231 { FC_ULP_SAMETYPE, "Same ULP Type" },
232 232 { FC_ABORTED, "Command Aborted" },
233 233 { FC_ABORT_FAILED, "Abort Failed" },
234 234 { FC_BADEXCHANGE, "Bad Exchange" },
235 235 { FC_BADWWN, "Bad World Wide Name" },
236 236 { FC_BADDEV, "Bad Device" },
237 237 { FC_BADCMD, "Bad Command" },
238 238 { FC_BADOBJECT, "Bad Object" },
239 239 { FC_BADPORT, "Bad Port" },
240 240 { FC_NOTTHISPORT, "Not on this Port" },
241 241 { FC_PREJECT, "Operation Prejected" },
242 242 { FC_FREJECT, "Operation Frejected" },
243 243 { FC_PBUSY, "Operation Pbusyed" },
244 244 { FC_FBUSY, "Operation Fbusyed" },
245 245 { FC_ALREADY, "Already done" },
246 246 { FC_LOGINREQ, "PLOGI Required" },
247 247 { FC_RESETFAIL, "Reset operation failed" },
248 248 { FC_INVALID_REQUEST, "Invalid Request" },
249 249 { FC_OUTOFBOUNDS, "Out of Bounds" },
250 250 { FC_TRAN_BUSY, "Command transport Busy" },
251 251 { FC_STATEC_BUSY, "State change Busy" },
252 252 { FC_DEVICE_BUSY, "Port driver is working on this device" }
253 253 };
254 254
255 255 fc_pkt_reason_t remote_stop_reasons [] = {
256 256 { FC_REASON_ABTS, "Abort Sequence" },
257 257 { FC_REASON_ABTX, "Abort Exchange" },
258 258 { FC_REASON_INVALID, NULL }
259 259 };
260 260
261 261 fc_pkt_reason_t general_reasons [] = {
262 262 { FC_REASON_HW_ERROR, "Hardware Error" },
263 263 { FC_REASON_SEQ_TIMEOUT, "Sequence Timeout" },
264 264 { FC_REASON_ABORTED, "Aborted" },
265 265 { FC_REASON_ABORT_FAILED, "Abort Failed" },
266 266 { FC_REASON_NO_CONNECTION, "No Connection" },
267 267 { FC_REASON_XCHG_DROPPED, "Exchange Dropped" },
268 268 { FC_REASON_ILLEGAL_FRAME, "Illegal Frame" },
269 269 { FC_REASON_ILLEGAL_LENGTH, "Illegal Length" },
270 270 { FC_REASON_UNSUPPORTED, "Unsuported" },
271 271 { FC_REASON_RX_BUF_TIMEOUT, "Receive Buffer Timeout" },
272 272 { FC_REASON_FCAL_OPN_FAIL, "FC AL Open Failed" },
273 273 { FC_REASON_OVERRUN, "Over run" },
274 274 { FC_REASON_QFULL, "Queue Full" },
275 275 { FC_REASON_ILLEGAL_REQ, "Illegal Request", },
276 276 { FC_REASON_PKT_BUSY, "Busy" },
277 277 { FC_REASON_OFFLINE, "Offline" },
278 278 { FC_REASON_BAD_XID, "Bad Exchange Id" },
279 279 { FC_REASON_XCHG_BSY, "Exchange Busy" },
280 280 { FC_REASON_NOMEM, "No Memory" },
281 281 { FC_REASON_BAD_SID, "Bad S_ID" },
282 282 { FC_REASON_NO_SEQ_INIT, "No Sequence Initiative" },
283 283 { FC_REASON_DIAG_BUSY, "Diagnostic Busy" },
284 284 { FC_REASON_DMA_ERROR, "DMA Error" },
285 285 { FC_REASON_CRC_ERROR, "CRC Error" },
286 286 { FC_REASON_ABORT_TIMEOUT, "Abort Timeout" },
287 287 { FC_REASON_FCA_UNIQUE, "FCA Unique" },
288 288 { FC_REASON_INVALID, NULL }
289 289 };
290 290
291 291 fc_pkt_reason_t rjt_reasons [] = {
292 292 { FC_REASON_INVALID_D_ID, "Invalid D_ID" },
293 293 { FC_REASON_INVALID_S_ID, "Invalid S_ID" },
294 294 { FC_REASON_TEMP_UNAVAILABLE, "Temporarily Unavailable" },
295 295 { FC_REASON_PERM_UNAVAILABLE, "Permamnently Unavailable" },
296 296 { FC_REASON_CLASS_NOT_SUPP, "Class Not Supported", },
297 297 { FC_REASON_DELIMTER_USAGE_ERROR,
298 298 "Delimeter Usage Error" },
299 299 { FC_REASON_TYPE_NOT_SUPP, "Type Not Supported" },
300 300 { FC_REASON_INVALID_LINK_CTRL, "Invalid Link Control" },
301 301 { FC_REASON_INVALID_R_CTL, "Invalid R_CTL" },
302 302 { FC_REASON_INVALID_F_CTL, "Invalid F_CTL" },
303 303 { FC_REASON_INVALID_OX_ID, "Invalid OX_ID" },
304 304 { FC_REASON_INVALID_RX_ID, "Invalid RX_ID" },
305 305 { FC_REASON_INVALID_SEQ_ID, "Invalid Sequence ID" },
306 306 { FC_REASON_INVALID_DF_CTL, "Invalid DF_CTL" },
307 307 { FC_REASON_INVALID_SEQ_CNT, "Invalid Sequence count" },
308 308 { FC_REASON_INVALID_PARAM, "Invalid Parameter" },
309 309 { FC_REASON_EXCH_ERROR, "Exchange Error" },
310 310 { FC_REASON_PROTOCOL_ERROR, "Protocol Error" },
311 311 { FC_REASON_INCORRECT_LENGTH, "Incorrect Length" },
312 312 { FC_REASON_UNEXPECTED_ACK, "Unexpected Ack" },
313 313 { FC_REASON_UNEXPECTED_LR, "Unexpected Link reset" },
314 314 { FC_REASON_LOGIN_REQUIRED, "Login Required" },
315 315 { FC_REASON_EXCESSIVE_SEQS, "Excessive Sequences"
316 316 " Attempted" },
317 317 { FC_REASON_EXCH_UNABLE, "Exchange incapable" },
318 318 { FC_REASON_ESH_NOT_SUPP, "Expiration Security Header "
319 319 "Not Supported" },
320 320 { FC_REASON_NO_FABRIC_PATH, "No Fabric Path" },
321 321 { FC_REASON_VENDOR_UNIQUE, "Vendor Unique" },
322 322 { FC_REASON_INVALID, NULL }
323 323 };
324 324
325 325 fc_pkt_reason_t n_port_busy_reasons [] = {
326 326 { FC_REASON_PHYSICAL_BUSY, "Physical Busy" },
327 327 { FC_REASON_N_PORT_RESOURCE_BSY, "Resource Busy" },
328 328 { FC_REASON_N_PORT_VENDOR_UNIQUE, "Vendor Unique" },
329 329 { FC_REASON_INVALID, NULL }
330 330 };
331 331
332 332 fc_pkt_reason_t f_busy_reasons [] = {
333 333 { FC_REASON_FABRIC_BSY, "Fabric Busy" },
334 334 { FC_REASON_N_PORT_BSY, "N_Port Busy" },
335 335 { FC_REASON_INVALID, NULL }
336 336 };
337 337
338 338 fc_pkt_reason_t ls_ba_rjt_reasons [] = {
339 339 { FC_REASON_INVALID_LA_CODE, "Invalid Link Application Code" },
340 340 { FC_REASON_LOGICAL_ERROR, "Logical Error" },
341 341 { FC_REASON_LOGICAL_BSY, "Logical Busy" },
342 342 { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject" },
343 343 { FC_REASON_CMD_UNABLE, "Unable to Perform Command" },
344 344 { FC_REASON_CMD_UNSUPPORTED, "Unsupported Command" },
345 345 { FC_REASON_VU_RJT, "Vendor Unique" },
346 346 { FC_REASON_INVALID, NULL }
347 347 };
348 348
349 349 fc_pkt_reason_t fs_rjt_reasons [] = {
350 350 { FC_REASON_FS_INVALID_CMD, "Invalid Command" },
351 351 { FC_REASON_FS_INVALID_VER, "Invalid Version" },
352 352 { FC_REASON_FS_LOGICAL_ERR, "Logical Error" },
353 353 { FC_REASON_FS_INVALID_IUSIZE, "Invalid IU Size" },
354 354 { FC_REASON_FS_LOGICAL_BUSY, "Logical Busy" },
355 355 { FC_REASON_FS_PROTOCOL_ERR, "Protocol Error" },
356 356 { FC_REASON_FS_CMD_UNABLE, "Unable to Perform Command" },
357 357 { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command" },
358 358 { FC_REASON_FS_VENDOR_UNIQUE, "Vendor Unique" },
359 359 { FC_REASON_INVALID, NULL }
360 360 };
361 361
362 362 fc_pkt_action_t n_port_busy_actions [] = {
363 363 { FC_ACTION_SEQ_TERM_RETRY, "Retry terminated Sequence" },
364 364 { FC_ACTION_SEQ_ACTIVE_RETRY, "Retry Active Sequence" },
365 365 { FC_REASON_INVALID, NULL }
366 366 };
367 367
368 368 fc_pkt_action_t rjt_timeout_actions [] = {
369 369 { FC_ACTION_RETRYABLE, "Retryable" },
370 370 { FC_ACTION_NON_RETRYABLE, "Non Retryable" },
371 371 { FC_REASON_INVALID, NULL }
372 372 };
373 373
374 374 fc_pkt_expln_t ba_rjt_explns [] = {
375 375 { FC_EXPLN_NONE, "No Explanation" },
376 376 { FC_EXPLN_INVALID_OX_RX_ID, "Invalid X_ID" },
377 377 { FC_EXPLN_SEQ_ABORTED, "Sequence Aborted" },
378 378 { FC_EXPLN_INVALID, NULL }
379 379 };
380 380
381 381 fc_pkt_error_t fc_pkt_errlist[] = {
382 382 {
383 383 FC_PKT_SUCCESS,
384 384 "Operation Success",
385 385 NULL,
386 386 NULL,
387 387 NULL
388 388 },
389 389 { FC_PKT_REMOTE_STOP,
390 390 "Remote Stop",
391 391 remote_stop_reasons,
392 392 NULL,
393 393 NULL
394 394 },
395 395 {
396 396 FC_PKT_LOCAL_RJT,
397 397 "Local Reject",
398 398 general_reasons,
399 399 rjt_timeout_actions,
400 400 NULL
401 401 },
402 402 {
403 403 FC_PKT_NPORT_RJT,
404 404 "N_Port Reject",
405 405 rjt_reasons,
406 406 rjt_timeout_actions,
407 407 NULL
408 408 },
409 409 {
410 410 FC_PKT_FABRIC_RJT,
411 411 "Fabric Reject",
412 412 rjt_reasons,
413 413 rjt_timeout_actions,
414 414 NULL
415 415 },
416 416 {
417 417 FC_PKT_LOCAL_BSY,
418 418 "Local Busy",
419 419 general_reasons,
420 420 NULL,
421 421 NULL,
422 422 },
423 423 {
424 424 FC_PKT_TRAN_BSY,
425 425 "Transport Busy",
426 426 general_reasons,
427 427 NULL,
428 428 NULL,
429 429 },
430 430 {
431 431 FC_PKT_NPORT_BSY,
432 432 "N_Port Busy",
433 433 n_port_busy_reasons,
434 434 n_port_busy_actions,
435 435 NULL
436 436 },
437 437 {
438 438 FC_PKT_FABRIC_BSY,
439 439 "Fabric Busy",
440 440 f_busy_reasons,
441 441 NULL,
442 442 NULL,
443 443 },
444 444 {
445 445 FC_PKT_LS_RJT,
446 446 "Link Service Reject",
447 447 ls_ba_rjt_reasons,
448 448 NULL,
449 449 NULL,
450 450 },
451 451 {
452 452 FC_PKT_BA_RJT,
453 453 "Basic Reject",
454 454 ls_ba_rjt_reasons,
455 455 NULL,
456 456 ba_rjt_explns,
457 457 },
458 458 {
459 459 FC_PKT_TIMEOUT,
460 460 "Timeout",
461 461 general_reasons,
462 462 rjt_timeout_actions,
463 463 NULL
464 464 },
465 465 {
466 466 FC_PKT_FS_RJT,
467 467 "Fabric Switch Reject",
468 468 fs_rjt_reasons,
469 469 NULL,
470 470 NULL
471 471 },
472 472 {
473 473 FC_PKT_TRAN_ERROR,
474 474 "Packet Transport error",
475 475 general_reasons,
476 476 NULL,
477 477 NULL
478 478 },
479 479 {
480 480 FC_PKT_FAILURE,
481 481 "Packet Failure",
482 482 general_reasons,
483 483 NULL,
484 484 NULL
485 485 },
486 486 {
487 487 FC_PKT_PORT_OFFLINE,
488 488 "Port Offline",
489 489 NULL,
490 490 NULL,
491 491 NULL
492 492 },
493 493 {
494 494 FC_PKT_ELS_IN_PROGRESS,
495 495 "ELS is in Progress",
496 496 NULL,
497 497 NULL,
498 498 NULL
499 499 }
500 500 };
501 501
502 502 int
503 503 _init()
504 504 {
505 505 int rval;
506 506
507 507 rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
508 508 rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
509 509 mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
510 510 mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
511 511
512 512 fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
513 513 fctl_nwwn_table_size, KM_SLEEP);
514 514
515 515 fctl_ulp_modules = NULL;
516 516 fctl_fca_portlist = NULL;
517 517
518 518 fctl_job_cache = kmem_cache_create("fctl_cache",
519 519 sizeof (job_request_t), 8, fctl_cache_constructor,
520 520 fctl_cache_destructor, NULL, NULL, NULL, 0);
521 521
522 522 if (fctl_job_cache == NULL) {
523 523 kmem_free(fctl_nwwn_hash_table,
524 524 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
525 525 mutex_destroy(&fctl_nwwn_hash_mutex);
526 526 mutex_destroy(&fctl_port_lock);
527 527 rw_destroy(&fctl_ulp_lock);
528 528 rw_destroy(&fctl_mod_ports_lock);
529 529 return (ENOMEM);
530 530 }
531 531
532 532 if ((rval = mod_install(&modlinkage)) != 0) {
533 533 kmem_cache_destroy(fctl_job_cache);
534 534 kmem_free(fctl_nwwn_hash_table,
535 535 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
536 536 mutex_destroy(&fctl_nwwn_hash_mutex);
537 537 mutex_destroy(&fctl_port_lock);
538 538 rw_destroy(&fctl_ulp_lock);
539 539 rw_destroy(&fctl_mod_ports_lock);
540 540 }
541 541
542 542 return (rval);
543 543 }
544 544
545 545
546 546 /*
547 547 * The mod_uninstall code doesn't call _fini when
548 548 * there is living dependent module on fctl. So
549 549 * there is no need to be extra careful here ?
550 550 */
551 551 int
552 552 _fini()
553 553 {
554 554 int rval;
555 555
556 556 if ((rval = mod_remove(&modlinkage)) != 0) {
557 557 return (rval);
558 558 }
559 559
560 560 kmem_cache_destroy(fctl_job_cache);
561 561 kmem_free(fctl_nwwn_hash_table,
562 562 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
563 563 mutex_destroy(&fctl_nwwn_hash_mutex);
564 564 mutex_destroy(&fctl_port_lock);
565 565 rw_destroy(&fctl_ulp_lock);
566 566 rw_destroy(&fctl_mod_ports_lock);
567 567
568 568 return (rval);
569 569 }
570 570
571 571
572 572 int
573 573 _info(struct modinfo *modinfo_p)
574 574 {
575 575 return (mod_info(&modlinkage, modinfo_p));
576 576 }
577 577
578 578
579 579 /* ARGSUSED */
580 580 static int
581 581 fctl_cache_constructor(void *buf, void *cdarg, int kmflag)
582 582 {
583 583 job_request_t *job = (job_request_t *)buf;
584 584
585 585 mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
586 586 sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
587 587 sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
588 588
589 589 return (0);
590 590 }
591 591
592 592
593 593 /* ARGSUSED */
594 594 static void
595 595 fctl_cache_destructor(void *buf, void *cdarg)
596 596 {
597 597 job_request_t *job = (job_request_t *)buf;
598 598
599 599 sema_destroy(&job->job_fctl_sema);
600 600 sema_destroy(&job->job_port_sema);
601 601 mutex_destroy(&job->job_mutex);
602 602 }
603 603
604 604
605 605 /*
606 606 * fc_ulp_add:
607 607 * Add a ULP module
608 608 *
609 609 * Return Codes:
610 610 * FC_ULP_SAMEMODULE
611 611 * FC_SUCCESS
612 612 * FC_FAILURE
613 613 *
614 614 * fc_ulp_add prints a warning message if there is already a
615 615 * similar ULP type attached and this is unlikely to change as
616 616 * we trudge along. Further, this function returns a failure
617 617 * code if the same module attempts to add more than once for
618 618 * the same FC-4 type.
619 619 */
620 620 int
621 621 fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
622 622 {
623 623 fc_ulp_module_t *mod;
624 624 fc_ulp_module_t *prev;
625 625 job_request_t *job;
626 626 fc_ulp_list_t *new;
627 627 fc_fca_port_t *fca_port;
628 628 int ntry = 0;
629 629
630 630 ASSERT(ulp_info != NULL);
631 631
632 632 /*
633 633 * Make sure ulp_rev matches fctl version.
634 634 * Whenever non-private data structure or non-static interface changes,
635 635 * we should use an increased FCTL_ULP_MODREV_# number here and in all
636 636 * ulps to prevent version mismatch.
637 637 */
638 638 if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
639 639 cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
640 640 " ULP %s would not be loaded", ulp_info->ulp_name,
641 641 ulp_info->ulp_name);
642 642 return (FC_BADULP);
643 643 }
644 644
645 645 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
646 646 ASSERT(new != NULL);
↓ open down ↓ |
646 lines elided |
↑ open up ↑ |
647 647
648 648 mutex_enter(&fctl_ulp_list_mutex);
649 649 new->ulp_info = ulp_info;
650 650 if (fctl_ulp_list != NULL) {
651 651 new->ulp_next = fctl_ulp_list;
652 652 }
653 653 fctl_ulp_list = new;
654 654 mutex_exit(&fctl_ulp_list_mutex);
655 655
656 656 while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
657 - delay(drv_usectohz(1000000));
657 + delay(drv_sectohz(1));
658 658 if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
659 659 fc_ulp_list_t *list;
660 660 fc_ulp_list_t *last;
661 661 mutex_enter(&fctl_ulp_list_mutex);
662 662 for (last = NULL, list = fctl_ulp_list; list != NULL;
663 663 list = list->ulp_next) {
664 664 if (list->ulp_info == ulp_info) {
665 665 break;
666 666 }
667 667 last = list;
668 668 }
669 669
670 670 if (list) {
671 671 if (last) {
672 672 last->ulp_next = list->ulp_next;
673 673 } else {
674 674 fctl_ulp_list = list->ulp_next;
675 675 }
676 676 kmem_free(list, sizeof (*list));
677 677 }
678 678 mutex_exit(&fctl_ulp_list_mutex);
679 679 cmn_err(CE_WARN, "fctl: ULP %s unable to load",
680 680 ulp_info->ulp_name);
681 681 return (FC_FAILURE);
682 682 }
683 683 }
684 684
685 685 for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
686 686 ASSERT(mod->mod_info != NULL);
687 687
688 688 if (ulp_info == mod->mod_info &&
689 689 ulp_info->ulp_type == mod->mod_info->ulp_type) {
690 690 rw_exit(&fctl_ulp_lock);
691 691 return (FC_ULP_SAMEMODULE);
692 692 }
693 693
694 694 if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
695 695 cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
696 696 ulp_info->ulp_type);
697 697 }
698 698 prev = mod;
699 699 }
700 700
701 701 mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
702 702 mod->mod_info = ulp_info;
703 703 mod->mod_next = NULL;
704 704
705 705 if (prev) {
706 706 prev->mod_next = mod;
707 707 } else {
708 708 fctl_ulp_modules = mod;
709 709 }
710 710
711 711 /*
712 712 * Schedule a job to each port's job_handler
713 713 * thread to attach their ports with this ULP.
714 714 */
715 715 mutex_enter(&fctl_port_lock);
716 716 for (fca_port = fctl_fca_portlist; fca_port != NULL;
717 717 fca_port = fca_port->port_next) {
718 718 job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
719 719 NULL, NULL, KM_SLEEP);
720 720
721 721 fctl_enque_job(fca_port->port_handle, job);
722 722 }
723 723 mutex_exit(&fctl_port_lock);
724 724
725 725 rw_exit(&fctl_ulp_lock);
726 726
727 727 return (FC_SUCCESS);
728 728 }
729 729
730 730
731 731 /*
732 732 * fc_ulp_remove
733 733 * Remove a ULP module
734 734 *
735 735 * A misbehaving ULP may call this routine while I/Os are in progress.
736 736 * Currently there is no mechanism to detect it to fail such a request.
737 737 *
738 738 * Return Codes:
739 739 * FC_SUCCESS
740 740 * FC_FAILURE
741 741 */
742 742 int
743 743 fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
744 744 {
745 745 fc_ulp_module_t *mod;
746 746 fc_ulp_list_t *list;
747 747 fc_ulp_list_t *last;
748 748 fc_ulp_module_t *prev;
749 749
750 750 mutex_enter(&fctl_ulp_list_mutex);
751 751
752 752 for (last = NULL, list = fctl_ulp_list; list != NULL;
753 753 list = list->ulp_next) {
754 754 if (list->ulp_info == ulp_info) {
755 755 break;
756 756 }
757 757 last = list;
758 758 }
759 759
760 760 if (list) {
761 761 if (last) {
762 762 last->ulp_next = list->ulp_next;
763 763 } else {
764 764 fctl_ulp_list = list->ulp_next;
765 765 }
766 766 kmem_free(list, sizeof (*list));
767 767 }
768 768
769 769 mutex_exit(&fctl_ulp_list_mutex);
770 770
771 771 rw_enter(&fctl_ulp_lock, RW_WRITER);
772 772
773 773 for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
774 774 mod = mod->mod_next) {
775 775 if (mod->mod_info == ulp_info) {
776 776 break;
777 777 }
778 778 prev = mod;
779 779 }
780 780
781 781 if (mod) {
782 782 fc_ulp_ports_t *next;
783 783
784 784 if (prev) {
785 785 prev->mod_next = mod->mod_next;
786 786 } else {
787 787 fctl_ulp_modules = mod->mod_next;
788 788 }
789 789
790 790 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
791 791
792 792 while ((next = mod->mod_ports) != NULL) {
793 793 mod->mod_ports = next->port_next;
794 794 fctl_dealloc_ulp_port(next);
795 795 }
796 796
797 797 rw_exit(&fctl_mod_ports_lock);
798 798 rw_exit(&fctl_ulp_lock);
799 799
800 800 kmem_free(mod, sizeof (*mod));
801 801
802 802 return (FC_SUCCESS);
803 803 }
804 804 rw_exit(&fctl_ulp_lock);
805 805
806 806 return (FC_FAILURE);
807 807 }
808 808
809 809
810 810 /*
811 811 * The callers typically cache allocate the packet, complete the
812 812 * DMA setup for pkt_cmd and pkt_resp fields of the packet and
813 813 * call this function to see if the FCA is interested in doing
814 814 * its own intialization. For example, socal may like to initialize
815 815 * the soc_hdr which is pointed to by the pkt_fca_private field
816 816 * and sitting right below fc_packet_t in memory.
817 817 *
818 818 * The caller is required to ensure that pkt_pd is populated with the
819 819 * handle that it was given when the transport notified it about the
820 820 * device this packet is associated with. If there is no associated
821 821 * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an
822 822 * increment of the reference count for said pd. When the packet is freed,
823 823 * the reference count will be decremented. This reference count, in
824 824 * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
825 825 * will not wink out of existence while there is a packet outstanding.
826 826 *
827 827 * This function and fca_init_pkt must not perform any operations that
828 828 * would result in a call back to the ULP, as the ULP may be required
829 829 * to hold a mutex across this call to ensure that the pd in question
830 830 * won't go away prior the call to fc_ulp_transport.
831 831 *
832 832 * ULPs are responsible for using the handles they are given during state
833 833 * change callback processing in a manner that ensures consistency. That
834 834 * is, they must be aware that they could be processing a state change
835 835 * notification that tells them the device associated with a particular
836 836 * handle has gone away at the same time they are being asked to
837 837 * initialize a packet using that handle. ULPs must therefore ensure
838 838 * that their state change processing and packet initialization code
839 839 * paths are sufficiently synchronized to avoid the use of an
840 840 * invalidated handle in any fc_packet_t struct that is passed to the
841 841 * fc_ulp_init_packet() function.
842 842 */
843 843 int
844 844 fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
845 845 {
846 846 int rval;
847 847 fc_local_port_t *port = port_handle;
848 848 fc_remote_port_t *pd;
849 849
850 850 ASSERT(pkt != NULL);
851 851
852 852 pd = pkt->pkt_pd;
853 853
854 854 /* Call the FCA driver's fca_init_pkt entry point function. */
855 855 rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
856 856
857 857 if ((rval == FC_SUCCESS) && (pd != NULL)) {
858 858 /*
859 859 * A !NULL pd here must still be a valid
860 860 * reference to the fc_remote_port_t.
861 861 */
862 862 mutex_enter(&pd->pd_mutex);
863 863 ASSERT(pd->pd_ref_count >= 0);
864 864 pd->pd_ref_count++;
865 865 mutex_exit(&pd->pd_mutex);
866 866 }
867 867
868 868 return (rval);
869 869 }
870 870
871 871
872 872 /*
873 873 * This function is called before destroying the cache allocated
874 874 * fc_packet to free up (and uninitialize) any resource specially
875 875 * allocated by the FCA driver during tran_init_pkt().
876 876 *
877 877 * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
878 878 * the pd_ref_count reference count is decremented for the indicated
879 879 * fc_remote_port_t struct.
880 880 */
881 881 int
882 882 fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
883 883 {
884 884 int rval;
885 885 fc_local_port_t *port = port_handle;
886 886 fc_remote_port_t *pd;
887 887
888 888 ASSERT(pkt != NULL);
889 889
890 890 pd = pkt->pkt_pd;
891 891
892 892 /* Call the FCA driver's fca_un_init_pkt entry point function */
893 893 rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
894 894
895 895 if ((rval == FC_SUCCESS) && (pd != NULL)) {
896 896 mutex_enter(&pd->pd_mutex);
897 897
898 898 ASSERT(pd->pd_ref_count > 0);
899 899 pd->pd_ref_count--;
900 900
901 901 /*
902 902 * If at this point the state of this fc_remote_port_t
903 903 * struct is PORT_DEVICE_INVALID, it probably means somebody
904 904 * is cleaning up old (e.g. retried) packets. If the
905 905 * pd_ref_count has also dropped to zero, it's time to
906 906 * deallocate this fc_remote_port_t struct.
907 907 */
908 908 if (pd->pd_state == PORT_DEVICE_INVALID &&
909 909 pd->pd_ref_count == 0) {
910 910 fc_remote_node_t *node = pd->pd_remote_nodep;
911 911
912 912 mutex_exit(&pd->pd_mutex);
913 913
914 914 /*
915 915 * Also deallocate the associated fc_remote_node_t
916 916 * struct if it has no other associated
917 917 * fc_remote_port_t structs.
918 918 */
919 919 if ((fctl_destroy_remote_port(port, pd) == 0) &&
920 920 (node != NULL)) {
921 921 fctl_destroy_remote_node(node);
922 922 }
923 923 return (rval);
924 924 }
925 925
926 926 mutex_exit(&pd->pd_mutex);
927 927 }
928 928
929 929 return (rval);
930 930 }
931 931
932 932
933 933 int
934 934 fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
935 935 int flag)
936 936 {
937 937 int job_code;
938 938 fc_local_port_t *port;
939 939 job_request_t *job;
940 940 fc_portmap_t *tmp_map;
941 941 uint32_t tmp_len;
942 942 fc_portmap_t *change_list = NULL;
943 943 uint32_t listlen = 0;
944 944
945 945 port = port_handle;
946 946
947 947 mutex_enter(&port->fp_mutex);
948 948 if (port->fp_statec_busy) {
949 949 mutex_exit(&port->fp_mutex);
950 950 return (FC_STATEC_BUSY);
951 951 }
952 952
953 953 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
954 954 mutex_exit(&port->fp_mutex);
955 955 return (FC_OFFLINE);
956 956 }
957 957
958 958 if (port->fp_dev_count && (port->fp_dev_count ==
959 959 port->fp_total_devices)) {
960 960 mutex_exit(&port->fp_mutex);
961 961 fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
962 962 if (listlen > *len) {
963 963 tmp_map = (fc_portmap_t *)kmem_zalloc(
964 964 listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
965 965 if (tmp_map == NULL) {
966 966 return (FC_NOMEM);
967 967 }
968 968 if (*map) {
969 969 kmem_free(*map, (*len) * sizeof (fc_portmap_t));
970 970 }
971 971 *map = tmp_map;
972 972 }
973 973 if (change_list) {
974 974 bcopy(change_list, *map,
975 975 listlen * sizeof (fc_portmap_t));
976 976 kmem_free(change_list, listlen * sizeof (fc_portmap_t));
977 977 }
978 978 *len = listlen;
979 979 } else {
980 980 mutex_exit(&port->fp_mutex);
981 981
982 982 switch (flag) {
983 983 case FC_ULP_PLOGI_DONTCARE:
984 984 job_code = JOB_PORT_GETMAP;
985 985 break;
986 986
987 987 case FC_ULP_PLOGI_PRESERVE:
988 988 job_code = JOB_PORT_GETMAP_PLOGI_ALL;
989 989 break;
990 990
991 991 default:
992 992 return (FC_INVALID_REQUEST);
993 993 }
994 994 /*
995 995 * Submit a job request to the job handler
996 996 * thread to get the map and wait
997 997 */
998 998 job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
999 999 job->job_private = (opaque_t)map;
1000 1000 job->job_arg = (opaque_t)len;
1001 1001 fctl_enque_job(port, job);
1002 1002
1003 1003 fctl_jobwait(job);
1004 1004 /*
1005 1005 * The result of the last I/O operation is
1006 1006 * in job_code. We don't care to look at it
1007 1007 * Rather we look at the number of devices
1008 1008 * that are found to fill out the map for
1009 1009 * ULPs.
1010 1010 */
1011 1011 fctl_dealloc_job(job);
1012 1012 }
1013 1013
1014 1014 /*
1015 1015 * If we're here, we're returning a map to the caller, which means
1016 1016 * we'd better make sure every pd in that map has the
1017 1017 * PD_GIVEN_TO_ULPS flag set.
1018 1018 */
1019 1019
1020 1020 tmp_len = *len;
1021 1021 tmp_map = *map;
1022 1022
1023 1023 while (tmp_len-- != 0) {
1024 1024 if (tmp_map->map_state != PORT_DEVICE_INVALID) {
1025 1025 fc_remote_port_t *pd =
1026 1026 (fc_remote_port_t *)tmp_map->map_pd;
1027 1027 mutex_enter(&pd->pd_mutex);
1028 1028 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1029 1029 mutex_exit(&pd->pd_mutex);
1030 1030 }
1031 1031 tmp_map++;
1032 1032 }
1033 1033
1034 1034 return (FC_SUCCESS);
1035 1035 }
1036 1036
1037 1037
1038 1038 int
1039 1039 fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
1040 1040 {
1041 1041 int rval = FC_SUCCESS;
1042 1042 int job_flags;
1043 1043 uint32_t count;
1044 1044 fc_packet_t **tmp_array;
1045 1045 job_request_t *job;
1046 1046 fc_local_port_t *port = port_handle;
1047 1047 fc_ulp_rscn_info_t *rscnp =
1048 1048 (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
1049 1049
1050 1050 /*
1051 1051 * If the port is OFFLINE, or if the port driver is
1052 1052 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1053 1053 * PLOGI operations
1054 1054 */
1055 1055 mutex_enter(&port->fp_mutex);
1056 1056 if (port->fp_statec_busy) {
1057 1057 mutex_exit(&port->fp_mutex);
1058 1058 return (FC_STATEC_BUSY);
1059 1059 }
1060 1060
1061 1061 if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1062 1062 (port->fp_soft_state &
1063 1063 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1064 1064 mutex_exit(&port->fp_mutex);
1065 1065 return (FC_OFFLINE);
1066 1066 }
1067 1067
1068 1068 /*
1069 1069 * If the rscn count in the packet is not the same as the rscn count
1070 1070 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1071 1071 */
1072 1072 if ((rscnp != NULL) &&
1073 1073 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1074 1074 (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1075 1075 mutex_exit(&port->fp_mutex);
1076 1076 return (FC_DEVICE_BUSY_NEW_RSCN);
1077 1077 }
1078 1078
1079 1079 mutex_exit(&port->fp_mutex);
1080 1080
1081 1081 tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
1082 1082 for (count = 0; count < listlen; count++) {
1083 1083 tmp_array[count] = ulp_pkt[count];
1084 1084 }
1085 1085
1086 1086 job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
1087 1087 ? 0 : JOB_TYPE_FCTL_ASYNC;
1088 1088
1089 1089 #ifdef DEBUG
1090 1090 {
1091 1091 int next;
1092 1092 int count;
1093 1093 int polled;
1094 1094
1095 1095 polled = ((ulp_pkt[0]->pkt_tran_flags) &
1096 1096 FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1097 1097
1098 1098 for (count = 0; count < listlen; count++) {
1099 1099 next = ((ulp_pkt[count]->pkt_tran_flags)
1100 1100 & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1101 1101 ASSERT(next == polled);
1102 1102 }
1103 1103 }
1104 1104 #endif
1105 1105
1106 1106 job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
1107 1107 job->job_ulp_pkts = tmp_array;
1108 1108 job->job_ulp_listlen = listlen;
1109 1109
1110 1110 while (listlen--) {
1111 1111 fc_packet_t *pkt;
1112 1112
1113 1113 pkt = tmp_array[listlen];
1114 1114 if (pkt->pkt_pd == NULL) {
1115 1115 pkt->pkt_state = FC_PKT_SUCCESS;
1116 1116 continue;
1117 1117 }
1118 1118
1119 1119 mutex_enter(&pkt->pkt_pd->pd_mutex);
1120 1120 if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
1121 1121 pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
1122 1122 /*
1123 1123 * Set the packet state and let the port
1124 1124 * driver call the completion routine
1125 1125 * from its thread
1126 1126 */
1127 1127 mutex_exit(&pkt->pkt_pd->pd_mutex);
1128 1128 pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
1129 1129 continue;
1130 1130 }
1131 1131
1132 1132 if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
1133 1133 pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
1134 1134 mutex_exit(&pkt->pkt_pd->pd_mutex);
1135 1135 pkt->pkt_state = FC_PKT_LOCAL_RJT;
1136 1136 continue;
1137 1137 }
1138 1138 mutex_exit(&pkt->pkt_pd->pd_mutex);
1139 1139 pkt->pkt_state = FC_PKT_SUCCESS;
1140 1140 }
1141 1141
1142 1142 fctl_enque_job(port, job);
1143 1143
1144 1144 if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
1145 1145 fctl_jobwait(job);
1146 1146 rval = job->job_result;
1147 1147 fctl_dealloc_job(job);
1148 1148 }
1149 1149
1150 1150 return (rval);
1151 1151 }
1152 1152
1153 1153
1154 1154 opaque_t
1155 1155 fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
1156 1156 int create)
1157 1157 {
1158 1158 fc_local_port_t *port;
1159 1159 job_request_t *job;
1160 1160 fc_remote_port_t *pd;
1161 1161
1162 1162 port = port_handle;
1163 1163 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1164 1164
1165 1165 if (pd != NULL) {
1166 1166 *error = FC_SUCCESS;
1167 1167 /*
1168 1168 * A ULP now knows about this pd, so mark it
1169 1169 */
1170 1170 mutex_enter(&pd->pd_mutex);
1171 1171 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1172 1172 mutex_exit(&pd->pd_mutex);
1173 1173 return (pd);
1174 1174 }
1175 1175
1176 1176 mutex_enter(&port->fp_mutex);
1177 1177 if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
1178 1178 uint32_t d_id;
1179 1179 fctl_ns_req_t *ns_cmd;
1180 1180
1181 1181 mutex_exit(&port->fp_mutex);
1182 1182
1183 1183 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1184 1184
1185 1185 if (job == NULL) {
1186 1186 *error = FC_NOMEM;
1187 1187 return (pd);
1188 1188 }
1189 1189
1190 1190 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
1191 1191 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
1192 1192 0, KM_SLEEP);
1193 1193
1194 1194 if (ns_cmd == NULL) {
1195 1195 fctl_dealloc_job(job);
1196 1196 *error = FC_NOMEM;
1197 1197 return (pd);
1198 1198 }
1199 1199 ns_cmd->ns_cmd_code = NS_GID_PN;
1200 1200 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
1201 1201
1202 1202 job->job_result = FC_SUCCESS;
1203 1203 job->job_private = (void *)ns_cmd;
1204 1204 job->job_counter = 1;
1205 1205 fctl_enque_job(port, job);
1206 1206 fctl_jobwait(job);
1207 1207
1208 1208 if (job->job_result != FC_SUCCESS) {
1209 1209 *error = job->job_result;
1210 1210 fctl_free_ns_cmd(ns_cmd);
1211 1211 fctl_dealloc_job(job);
1212 1212 return (pd);
1213 1213 }
1214 1214 d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
1215 1215 fctl_free_ns_cmd(ns_cmd);
1216 1216
1217 1217 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
1218 1218 sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
1219 1219 KM_SLEEP);
1220 1220 ASSERT(ns_cmd != NULL);
1221 1221
1222 1222 ns_cmd->ns_gan_max = 1;
1223 1223 ns_cmd->ns_cmd_code = NS_GA_NXT;
1224 1224 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
1225 1225 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
1226 1226 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
1227 1227
1228 1228 job->job_result = FC_SUCCESS;
1229 1229 job->job_private = (void *)ns_cmd;
1230 1230 job->job_counter = 1;
1231 1231 fctl_enque_job(port, job);
1232 1232 fctl_jobwait(job);
1233 1233
1234 1234 fctl_free_ns_cmd(ns_cmd);
1235 1235 if (job->job_result != FC_SUCCESS) {
1236 1236 *error = job->job_result;
1237 1237 fctl_dealloc_job(job);
1238 1238 return (pd);
1239 1239 }
1240 1240 fctl_dealloc_job(job);
1241 1241
1242 1242 /*
1243 1243 * Check if the port device is created now.
1244 1244 */
1245 1245 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1246 1246
1247 1247 if (pd == NULL) {
1248 1248 *error = FC_FAILURE;
1249 1249 } else {
1250 1250 *error = FC_SUCCESS;
1251 1251
1252 1252 /*
1253 1253 * A ULP now knows about this pd, so mark it
1254 1254 */
1255 1255 mutex_enter(&pd->pd_mutex);
1256 1256 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1257 1257 mutex_exit(&pd->pd_mutex);
1258 1258 }
1259 1259 } else {
1260 1260 mutex_exit(&port->fp_mutex);
1261 1261 *error = FC_FAILURE;
1262 1262 }
1263 1263
1264 1264 return (pd);
1265 1265 }
1266 1266
1267 1267
1268 1268 /*
1269 1269 * If a NS object exists in the host and query is performed
1270 1270 * on that object, we should retrieve it from our basket
1271 1271 * and return it right here, there by saving a request going
1272 1272 * all the up to the Name Server.
1273 1273 */
1274 1274 int
1275 1275 fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
1276 1276 {
1277 1277 int rval;
1278 1278 int fabric;
1279 1279 job_request_t *job;
1280 1280 fctl_ns_req_t *ns_cmd;
1281 1281 fc_local_port_t *port = port_handle;
1282 1282
1283 1283 mutex_enter(&port->fp_mutex);
1284 1284 fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
1285 1285 mutex_exit(&port->fp_mutex);
1286 1286
1287 1287 /*
1288 1288 * Name server query can't be performed for devices not in Fabric
1289 1289 */
1290 1290 if (!fabric && pd) {
1291 1291 return (FC_BADOBJECT);
1292 1292 }
1293 1293
1294 1294 if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
1295 1295 if (pd == NULL) {
1296 1296 rval = fctl_update_host_ns_values(port, ns_req);
1297 1297 if (rval != FC_SUCCESS) {
1298 1298 return (rval);
1299 1299 }
1300 1300 } else {
1301 1301 /*
1302 1302 * Guess what, FC-GS-2 currently prohibits (not
1303 1303 * in the strongest language though) setting of
1304 1304 * NS object values by other ports. But we might
1305 1305 * get that changed to at least accommodate setting
1306 1306 * symbolic node/port names - But if disks/tapes
1307 1307 * were going to provide a method to set these
1308 1308 * values directly (which in turn might register
1309 1309 * with the NS when they come up; yep, for that
1310 1310 * to happen the disks will have to be very well
1311 1311 * behaved Fabric citizen) we won't need to
1312 1312 * register the symbolic port/node names for
1313 1313 * other ports too (rather send down SCSI commands
1314 1314 * to the devices to set the names)
1315 1315 *
1316 1316 * Be that as it may, let's continue to fail
1317 1317 * registration requests for other ports. period.
1318 1318 */
1319 1319 return (FC_BADOBJECT);
1320 1320 }
1321 1321
1322 1322 if (!fabric) {
1323 1323 return (FC_SUCCESS);
1324 1324 }
1325 1325 } else if (!fabric) {
1326 1326 return (fctl_retrieve_host_ns_values(port, ns_req));
1327 1327 }
1328 1328
1329 1329 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1330 1330 ASSERT(job != NULL);
1331 1331
1332 1332 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
1333 1333 ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
1334 1334 ASSERT(ns_cmd != NULL);
1335 1335 ns_cmd->ns_cmd_code = ns_req->ns_cmd;
1336 1336 bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
1337 1337 ns_req->ns_req_len);
1338 1338
1339 1339 job->job_private = (void *)ns_cmd;
1340 1340 fctl_enque_job(port, job);
1341 1341 fctl_jobwait(job);
1342 1342 rval = job->job_result;
1343 1343
1344 1344 if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
1345 1345 bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
1346 1346 ns_cmd->ns_data_len);
1347 1347 }
1348 1348 bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
1349 1349 sizeof (fc_ct_header_t));
1350 1350
1351 1351 fctl_free_ns_cmd(ns_cmd);
1352 1352 fctl_dealloc_job(job);
1353 1353
1354 1354 return (rval);
1355 1355 }
1356 1356
1357 1357
1358 1358 int
1359 1359 fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
1360 1360 {
1361 1361 int rval;
1362 1362 fc_local_port_t *port;
1363 1363 fc_remote_port_t *pd, *newpd;
1364 1364 fc_ulp_rscn_info_t *rscnp =
1365 1365 (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1366 1366
1367 1367 port = port_handle;
1368 1368
1369 1369 if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
1370 1370 return (port->fp_fca_tran->fca_transport(
1371 1371 port->fp_fca_handle, pkt));
1372 1372 }
1373 1373
1374 1374 mutex_enter(&port->fp_mutex);
1375 1375 if (port->fp_statec_busy) {
1376 1376 mutex_exit(&port->fp_mutex);
1377 1377 return (FC_STATEC_BUSY);
1378 1378 }
1379 1379
1380 1380 /* A locus of race conditions */
1381 1381 if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
1382 1382 (port->fp_soft_state &
1383 1383 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1384 1384 mutex_exit(&port->fp_mutex);
1385 1385 return (FC_OFFLINE);
1386 1386 }
1387 1387
1388 1388 /*
1389 1389 * If the rscn count in the packet is not the same as the rscn count
1390 1390 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1391 1391 */
1392 1392 if ((rscnp != NULL) &&
1393 1393 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1394 1394 (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1395 1395 mutex_exit(&port->fp_mutex);
1396 1396 return (FC_DEVICE_BUSY_NEW_RSCN);
1397 1397 }
1398 1398
1399 1399 pd = pkt->pkt_pd;
1400 1400 if (pd) {
1401 1401 if (pd->pd_type == PORT_DEVICE_OLD ||
1402 1402 pd->pd_state == PORT_DEVICE_INVALID) {
1403 1403
1404 1404 newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
1405 1405 &pd->pd_port_name);
1406 1406
1407 1407 /*
1408 1408 * The remote port (pd) in the packet is no longer
1409 1409 * usable, as the old pd still exists we can use the
1410 1410 * WWN to check if we have a current pd for the device
1411 1411 * we want. Either way we continue with the old logic
1412 1412 * whether we have a new pd or not, as the new pd
1413 1413 * could be bad, or have become unusable.
1414 1414 */
1415 1415 if ((newpd) && (newpd != pd)) {
1416 1416
1417 1417 /*
1418 1418 * There is a better remote port (pd) to try,
1419 1419 * so we need to fix the reference counts, etc.
1420 1420 */
1421 1421 mutex_enter(&newpd->pd_mutex);
1422 1422 newpd->pd_ref_count++;
1423 1423 pkt->pkt_pd = newpd;
1424 1424 mutex_exit(&newpd->pd_mutex);
1425 1425
1426 1426 mutex_enter(&pd->pd_mutex);
1427 1427 pd->pd_ref_count--;
1428 1428 if ((pd->pd_state == PORT_DEVICE_INVALID) &&
1429 1429 (pd->pd_ref_count == 0)) {
1430 1430 fc_remote_node_t *node =
1431 1431 pd->pd_remote_nodep;
1432 1432
1433 1433 mutex_exit(&pd->pd_mutex);
1434 1434 mutex_exit(&port->fp_mutex);
1435 1435
1436 1436 /*
1437 1437 * This will create another PD hole
1438 1438 * where we have a reference to a pd,
1439 1439 * but someone else could remove it.
1440 1440 */
1441 1441 if ((fctl_destroy_remote_port(port, pd)
1442 1442 == 0) && (node != NULL)) {
1443 1443 fctl_destroy_remote_node(node);
1444 1444 }
1445 1445 mutex_enter(&port->fp_mutex);
1446 1446 } else {
1447 1447 mutex_exit(&pd->pd_mutex);
1448 1448 }
1449 1449 pd = newpd;
1450 1450 }
1451 1451 }
1452 1452
1453 1453 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1454 1454 rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1455 1455 FC_LOGINREQ : FC_BADDEV;
1456 1456 mutex_exit(&port->fp_mutex);
1457 1457 return (rval);
1458 1458 }
1459 1459
1460 1460 if (pd->pd_flags != PD_IDLE) {
1461 1461 mutex_exit(&port->fp_mutex);
1462 1462 return (FC_DEVICE_BUSY);
1463 1463 }
1464 1464
1465 1465 if (pd->pd_type == PORT_DEVICE_OLD ||
1466 1466 pd->pd_state == PORT_DEVICE_INVALID) {
1467 1467 mutex_exit(&port->fp_mutex);
1468 1468 return (FC_BADDEV);
1469 1469 }
1470 1470
1471 1471 } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
1472 1472 mutex_exit(&port->fp_mutex);
1473 1473 return (FC_BADPACKET);
1474 1474 }
1475 1475 mutex_exit(&port->fp_mutex);
1476 1476
1477 1477 return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
1478 1478 }
1479 1479
1480 1480
1481 1481 int
1482 1482 fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
1483 1483 {
1484 1484 int rval;
1485 1485 fc_local_port_t *port = port_handle;
1486 1486 fc_remote_port_t *pd;
1487 1487 fc_ulp_rscn_info_t *rscnp =
1488 1488 (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1489 1489
1490 1490 /*
1491 1491 * If the port is OFFLINE, or if the port driver is
1492 1492 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1493 1493 * ELS operations
1494 1494 */
1495 1495 mutex_enter(&port->fp_mutex);
1496 1496 if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1497 1497 (port->fp_soft_state &
1498 1498 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1499 1499 mutex_exit(&port->fp_mutex);
1500 1500 return (FC_OFFLINE);
1501 1501 }
1502 1502
1503 1503 if (port->fp_statec_busy) {
1504 1504 mutex_exit(&port->fp_mutex);
1505 1505 return (FC_STATEC_BUSY);
1506 1506 }
1507 1507
1508 1508 /*
1509 1509 * If the rscn count in the packet is not the same as the rscn count
1510 1510 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1511 1511 */
1512 1512 if ((rscnp != NULL) &&
1513 1513 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1514 1514 (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1515 1515 mutex_exit(&port->fp_mutex);
1516 1516 return (FC_DEVICE_BUSY_NEW_RSCN);
1517 1517 }
1518 1518
1519 1519 mutex_exit(&port->fp_mutex);
1520 1520
1521 1521 if ((pd = pkt->pkt_pd) != NULL) {
1522 1522 mutex_enter(&pd->pd_mutex);
1523 1523 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1524 1524 rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1525 1525 FC_LOGINREQ : FC_BADDEV;
1526 1526 mutex_exit(&pd->pd_mutex);
1527 1527 return (rval);
1528 1528 }
1529 1529
1530 1530 if (pd->pd_flags != PD_IDLE) {
1531 1531 mutex_exit(&pd->pd_mutex);
1532 1532 return (FC_DEVICE_BUSY);
1533 1533 }
1534 1534 if (pd->pd_type == PORT_DEVICE_OLD ||
1535 1535 pd->pd_state == PORT_DEVICE_INVALID) {
1536 1536 mutex_exit(&pd->pd_mutex);
1537 1537 return (FC_BADDEV);
1538 1538 }
1539 1539 mutex_exit(&pd->pd_mutex);
1540 1540 }
1541 1541
1542 1542 return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
1543 1543 }
1544 1544
1545 1545
1546 1546 int
1547 1547 fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
1548 1548 uint32_t type, uint64_t *tokens)
1549 1549 {
1550 1550 fc_local_port_t *port = port_handle;
1551 1551
1552 1552 return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
1553 1553 tokens, size, count, type));
1554 1554 }
1555 1555
1556 1556
1557 1557 int
1558 1558 fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1559 1559 {
1560 1560 fc_local_port_t *port = port_handle;
1561 1561
1562 1562 return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
1563 1563 count, tokens));
1564 1564 }
1565 1565
1566 1566
1567 1567 int
1568 1568 fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1569 1569 {
1570 1570 fc_local_port_t *port = port_handle;
1571 1571
1572 1572 return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
1573 1573 count, tokens));
1574 1574 }
1575 1575
1576 1576
1577 1577 int
1578 1578 fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
1579 1579 {
1580 1580 fc_local_port_t *port = port_handle;
1581 1581
1582 1582 return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
1583 1583 }
1584 1584
1585 1585
1586 1586 /*
1587 1587 * Submit an asynchronous request to the job handler if the sleep
1588 1588 * flag is set to KM_NOSLEEP, as such calls could have been made
1589 1589 * in interrupt contexts, and the goal is to avoid busy waiting,
1590 1590 * blocking on a conditional variable, a semaphore or any of the
1591 1591 * synchronization primitives. A noticeable draw back with this
1592 1592 * asynchronous request is that an FC_SUCCESS is returned long
1593 1593 * before the reset is complete (successful or not).
1594 1594 */
1595 1595 int
1596 1596 fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
1597 1597 {
1598 1598 int rval;
1599 1599 fc_local_port_t *port;
1600 1600 job_request_t *job;
1601 1601
1602 1602 port = port_handle;
1603 1603 /*
1604 1604 * Many a times, this function is called from interrupt
1605 1605 * contexts and there have been several dead locks and
1606 1606 * hangs - One of the simplest work arounds is to fib
1607 1607 * if a RESET is in progress.
1608 1608 */
1609 1609 mutex_enter(&port->fp_mutex);
1610 1610 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
1611 1611 mutex_exit(&port->fp_mutex);
1612 1612 return (FC_SUCCESS);
1613 1613 }
1614 1614
1615 1615 /*
1616 1616 * Ward off this reset if a state change is in progress.
1617 1617 */
1618 1618 if (port->fp_statec_busy) {
1619 1619 mutex_exit(&port->fp_mutex);
1620 1620 return (FC_STATEC_BUSY);
1621 1621 }
1622 1622 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
1623 1623 mutex_exit(&port->fp_mutex);
1624 1624
1625 1625 if (fctl_busy_port(port) != 0) {
1626 1626 mutex_enter(&port->fp_mutex);
1627 1627 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1628 1628 mutex_exit(&port->fp_mutex);
1629 1629 return (FC_FAILURE);
1630 1630 }
1631 1631
1632 1632 if (sleep == KM_SLEEP) {
1633 1633 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
1634 1634 ASSERT(job != NULL);
1635 1635
1636 1636 job->job_private = (void *)pwwn;
1637 1637 job->job_counter = 1;
1638 1638 fctl_enque_job(port, job);
1639 1639 fctl_jobwait(job);
1640 1640
1641 1641 mutex_enter(&port->fp_mutex);
1642 1642 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1643 1643 mutex_exit(&port->fp_mutex);
1644 1644
1645 1645 fctl_idle_port(port);
1646 1646
1647 1647 rval = job->job_result;
1648 1648 fctl_dealloc_job(job);
1649 1649 } else {
1650 1650 job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
1651 1651 fctl_link_reset_done, port, sleep);
1652 1652 if (job == NULL) {
1653 1653 mutex_enter(&port->fp_mutex);
1654 1654 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1655 1655 mutex_exit(&port->fp_mutex);
1656 1656 fctl_idle_port(port);
1657 1657 return (FC_NOMEM);
1658 1658 }
1659 1659 job->job_private = (void *)pwwn;
1660 1660 job->job_counter = 1;
1661 1661 fctl_priority_enque_job(port, job);
1662 1662 rval = FC_SUCCESS;
1663 1663 }
1664 1664
1665 1665 return (rval);
1666 1666 }
1667 1667
1668 1668
1669 1669 int
1670 1670 fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
1671 1671 {
1672 1672 int rval = FC_SUCCESS;
1673 1673 fc_local_port_t *port = port_handle;
1674 1674
1675 1675 switch (cmd) {
1676 1676 case FC_RESET_PORT:
1677 1677 rval = port->fp_fca_tran->fca_reset(
1678 1678 port->fp_fca_handle, FC_FCA_LINK_RESET);
1679 1679 break;
1680 1680
1681 1681 case FC_RESET_ADAPTER:
1682 1682 rval = port->fp_fca_tran->fca_reset(
1683 1683 port->fp_fca_handle, FC_FCA_RESET);
1684 1684 break;
1685 1685
1686 1686 case FC_RESET_DUMP:
1687 1687 rval = port->fp_fca_tran->fca_reset(
1688 1688 port->fp_fca_handle, FC_FCA_CORE);
1689 1689 break;
1690 1690
1691 1691 case FC_RESET_CRASH:
1692 1692 rval = port->fp_fca_tran->fca_reset(
1693 1693 port->fp_fca_handle, FC_FCA_RESET_CORE);
1694 1694 break;
1695 1695
1696 1696 default:
1697 1697 rval = FC_FAILURE;
1698 1698 }
1699 1699
1700 1700 return (rval);
1701 1701 }
1702 1702
1703 1703
1704 1704 int
1705 1705 fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
1706 1706 {
1707 1707 fc_local_port_t *port = port_handle;
1708 1708
1709 1709 /* Copy the login parameters */
1710 1710 *login_params = port->fp_service_params;
1711 1711 return (FC_SUCCESS);
1712 1712 }
1713 1713
1714 1714
1715 1715 int
1716 1716 fc_ulp_get_port_instance(opaque_t port_handle)
1717 1717 {
1718 1718 fc_local_port_t *port = port_handle;
1719 1719
1720 1720 return (port->fp_instance);
1721 1721 }
1722 1722
1723 1723
1724 1724 opaque_t
1725 1725 fc_ulp_get_port_handle(int port_instance)
1726 1726 {
1727 1727 opaque_t port_handle = NULL;
1728 1728 fc_fca_port_t *cur;
1729 1729
1730 1730 mutex_enter(&fctl_port_lock);
1731 1731 for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
1732 1732 if (cur->port_handle->fp_instance == port_instance) {
1733 1733 port_handle = (opaque_t)cur->port_handle;
1734 1734 break;
1735 1735 }
1736 1736 }
1737 1737 mutex_exit(&fctl_port_lock);
1738 1738
1739 1739 return (port_handle);
1740 1740 }
1741 1741
1742 1742
1743 1743 int
1744 1744 fc_ulp_error(int fc_errno, char **errmsg)
1745 1745 {
1746 1746 return (fctl_error(fc_errno, errmsg));
1747 1747 }
1748 1748
1749 1749
1750 1750 int
1751 1751 fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
1752 1752 char **action, char **expln)
1753 1753 {
1754 1754 return (fctl_pkt_error(pkt, state, reason, action, expln));
1755 1755 }
1756 1756
1757 1757
1758 1758 /*
1759 1759 * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
1760 1760 */
1761 1761 int
1762 1762 fc_ulp_is_name_present(caddr_t ulp_name)
1763 1763 {
1764 1764 int rval = FC_FAILURE;
1765 1765 fc_ulp_list_t *list;
1766 1766
1767 1767 mutex_enter(&fctl_ulp_list_mutex);
1768 1768 for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
1769 1769 if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
1770 1770 rval = FC_SUCCESS;
1771 1771 break;
1772 1772 }
1773 1773 }
1774 1774 mutex_exit(&fctl_ulp_list_mutex);
1775 1775
1776 1776 return (rval);
1777 1777 }
1778 1778
1779 1779
1780 1780 /*
1781 1781 * Return port WWN for a port Identifier
1782 1782 */
1783 1783 int
1784 1784 fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
1785 1785 {
1786 1786 int rval = FC_FAILURE;
1787 1787 fc_remote_port_t *pd;
1788 1788 fc_local_port_t *port = port_handle;
1789 1789
1790 1790 pd = fctl_get_remote_port_by_did(port, d_id.port_id);
1791 1791 if (pd != NULL) {
1792 1792 mutex_enter(&pd->pd_mutex);
1793 1793 *pwwn = pd->pd_port_name;
1794 1794 mutex_exit(&pd->pd_mutex);
1795 1795 rval = FC_SUCCESS;
1796 1796 }
1797 1797
1798 1798 return (rval);
1799 1799 }
1800 1800
1801 1801
1802 1802 /*
1803 1803 * Return a port map for a port WWN
1804 1804 */
1805 1805 int
1806 1806 fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
1807 1807 {
1808 1808 fc_local_port_t *port = port_handle;
1809 1809 fc_remote_node_t *node;
1810 1810 fc_remote_port_t *pd;
1811 1811
1812 1812 pd = fctl_get_remote_port_by_pwwn(port, bytes);
1813 1813 if (pd == NULL) {
1814 1814 return (FC_FAILURE);
1815 1815 }
1816 1816
1817 1817 mutex_enter(&pd->pd_mutex);
1818 1818 map->map_pwwn = pd->pd_port_name;
1819 1819 map->map_did = pd->pd_port_id;
1820 1820 map->map_hard_addr = pd->pd_hard_addr;
1821 1821 map->map_state = pd->pd_state;
1822 1822 map->map_type = pd->pd_type;
1823 1823 map->map_flags = 0;
1824 1824
1825 1825 ASSERT(map->map_type <= PORT_DEVICE_DELETE);
1826 1826
1827 1827 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
1828 1828
1829 1829 node = pd->pd_remote_nodep;
1830 1830 mutex_exit(&pd->pd_mutex);
1831 1831
1832 1832 if (node) {
1833 1833 mutex_enter(&node->fd_mutex);
1834 1834 map->map_nwwn = node->fd_node_name;
1835 1835 mutex_exit(&node->fd_mutex);
1836 1836 }
1837 1837 map->map_pd = pd;
1838 1838
1839 1839 return (FC_SUCCESS);
1840 1840 }
1841 1841
1842 1842
1843 1843 opaque_t
1844 1844 fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
1845 1845 {
1846 1846 fc_local_port_t *port = port_handle;
1847 1847
1848 1848 if (port->fp_fca_tran->fca_get_device == NULL) {
1849 1849 return (NULL);
1850 1850 }
1851 1851
1852 1852 return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
1853 1853 }
1854 1854
1855 1855
1856 1856 int
1857 1857 fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
1858 1858 {
1859 1859 int rval = FC_SUCCESS;
1860 1860 fc_local_port_t *port = port_handle;
1861 1861
1862 1862 if (port->fp_fca_tran->fca_notify) {
1863 1863 mutex_enter(&port->fp_mutex);
1864 1864 switch (cmd) {
1865 1865 case FC_NOTIFY_TARGET_MODE:
1866 1866 port->fp_options |= FP_TARGET_MODE;
1867 1867 break;
1868 1868 case FC_NOTIFY_NO_TARGET_MODE:
1869 1869 port->fp_options &= ~FP_TARGET_MODE;
1870 1870 break;
1871 1871 }
1872 1872 mutex_exit(&port->fp_mutex);
1873 1873 rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
1874 1874 }
1875 1875
1876 1876 return (rval);
1877 1877 }
1878 1878
1879 1879
1880 1880 void
1881 1881 fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1882 1882 {
1883 1883 fc_remote_port_t *pd =
1884 1884 fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1885 1885
1886 1886 if (pd) {
1887 1887 mutex_enter(&pd->pd_mutex);
1888 1888 pd->pd_aux_flags |= PD_DISABLE_RELOGIN;
1889 1889 mutex_exit(&pd->pd_mutex);
1890 1890 }
1891 1891 }
1892 1892
1893 1893
1894 1894 void
1895 1895 fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1896 1896 {
1897 1897 fc_remote_port_t *pd =
1898 1898 fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1899 1899
1900 1900 if (pd) {
1901 1901 mutex_enter(&pd->pd_mutex);
1902 1902 pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1903 1903 mutex_exit(&pd->pd_mutex);
1904 1904 }
1905 1905 }
1906 1906
1907 1907
1908 1908 /*
1909 1909 * fc_fca_init
1910 1910 * Overload the FCA bus_ops vector in its dev_ops with
1911 1911 * fctl_fca_busops to handle all the INITchilds for "sf"
1912 1912 * in one common place.
1913 1913 *
1914 1914 * Should be called from FCA _init routine.
1915 1915 */
1916 1916 void
1917 1917 fc_fca_init(struct dev_ops *fca_devops_p)
1918 1918 {
1919 1919 #ifndef __lock_lint
1920 1920 fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1921 1921 #endif /* __lock_lint */
1922 1922 }
1923 1923
1924 1924
1925 1925 /*
1926 1926 * fc_fca_attach
1927 1927 */
1928 1928 int
1929 1929 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1930 1930 {
1931 1931 /*
1932 1932 * When we are in a position to offer downward compatibility
1933 1933 * we should change the following check to allow lower revision
1934 1934 * of FCAs; But we aren't there right now.
1935 1935 */
1936 1936 if (tran->fca_version != FCTL_FCA_MODREV_5) {
1937 1937 const char *name = ddi_driver_name(fca_dip);
1938 1938
1939 1939 ASSERT(name != NULL);
1940 1940
1941 1941 cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
1942 1942 " please upgrade %s", name, name);
1943 1943 return (DDI_FAILURE);
1944 1944 }
1945 1945
1946 1946 ddi_set_driver_private(fca_dip, (caddr_t)tran);
1947 1947 return (DDI_SUCCESS);
1948 1948 }
1949 1949
1950 1950
1951 1951 /*
1952 1952 * fc_fca_detach
1953 1953 */
1954 1954 int
1955 1955 fc_fca_detach(dev_info_t *fca_dip)
1956 1956 {
1957 1957 ddi_set_driver_private(fca_dip, NULL);
1958 1958 return (DDI_SUCCESS);
1959 1959 }
1960 1960
1961 1961
1962 1962 /*
1963 1963 * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
1964 1964 * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
1965 1965 * Link Service responses such as BA_RJT and Extended Link Service response
1966 1966 * such as LS_RJT. If the response is a Link_Data Frame or something that
1967 1967 * this function doesn't understand return FC_FAILURE; Otherwise, fill out
1968 1968 * various fields (state, action, reason, expln) from the response gotten
1969 1969 * in the packet and return FC_SUCCESS.
1970 1970 */
1971 1971 int
1972 1972 fc_fca_update_errors(fc_packet_t *pkt)
1973 1973 {
1974 1974 int ret = FC_SUCCESS;
1975 1975
1976 1976 switch (pkt->pkt_resp_fhdr.r_ctl) {
1977 1977 case R_CTL_P_RJT: {
1978 1978 uint32_t prjt;
1979 1979
1980 1980 prjt = pkt->pkt_resp_fhdr.ro;
1981 1981 pkt->pkt_state = FC_PKT_NPORT_RJT;
1982 1982 pkt->pkt_action = (prjt & 0xFF000000) >> 24;
1983 1983 pkt->pkt_reason = (prjt & 0xFF0000) >> 16;
1984 1984 break;
1985 1985 }
1986 1986
1987 1987 case R_CTL_F_RJT: {
1988 1988 uint32_t frjt;
1989 1989
1990 1990 frjt = pkt->pkt_resp_fhdr.ro;
1991 1991 pkt->pkt_state = FC_PKT_FABRIC_RJT;
1992 1992 pkt->pkt_action = (frjt & 0xFF000000) >> 24;
1993 1993 pkt->pkt_reason = (frjt & 0xFF0000) >> 16;
1994 1994 break;
1995 1995 }
1996 1996
1997 1997 case R_CTL_P_BSY: {
1998 1998 uint32_t pbsy;
1999 1999
2000 2000 pbsy = pkt->pkt_resp_fhdr.ro;
2001 2001 pkt->pkt_state = FC_PKT_NPORT_BSY;
2002 2002 pkt->pkt_action = (pbsy & 0xFF000000) >> 24;
2003 2003 pkt->pkt_reason = (pbsy & 0xFF0000) >> 16;
2004 2004 break;
2005 2005 }
2006 2006
2007 2007 case R_CTL_F_BSY_LC:
2008 2008 case R_CTL_F_BSY_DF: {
2009 2009 uchar_t fbsy;
2010 2010
2011 2011 fbsy = pkt->pkt_resp_fhdr.type;
2012 2012 pkt->pkt_state = FC_PKT_FABRIC_BSY;
2013 2013 pkt->pkt_reason = (fbsy & 0xF0) >> 4;
2014 2014 break;
2015 2015 }
2016 2016
2017 2017 case R_CTL_LS_BA_RJT: {
2018 2018 uint32_t brjt;
2019 2019
2020 2020 brjt = *(uint32_t *)pkt->pkt_resp;
2021 2021 pkt->pkt_state = FC_PKT_BA_RJT;
2022 2022 pkt->pkt_reason = (brjt & 0xFF0000) >> 16;
2023 2023 pkt->pkt_expln = (brjt & 0xFF00) >> 8;
2024 2024 break;
2025 2025 }
2026 2026
2027 2027 case R_CTL_ELS_RSP: {
2028 2028 la_els_rjt_t *lsrjt;
2029 2029
2030 2030 lsrjt = (la_els_rjt_t *)pkt->pkt_resp;
2031 2031 if (lsrjt->ls_code.ls_code == LA_ELS_RJT) {
2032 2032 pkt->pkt_state = FC_PKT_LS_RJT;
2033 2033 pkt->pkt_reason = lsrjt->reason;
2034 2034 pkt->pkt_action = lsrjt->action;
2035 2035 break;
2036 2036 }
2037 2037 /* FALLTHROUGH */
2038 2038 }
2039 2039
2040 2040 default:
2041 2041 ret = FC_FAILURE;
2042 2042 break;
2043 2043 }
2044 2044
2045 2045 return (ret);
2046 2046 }
2047 2047
2048 2048
2049 2049 int
2050 2050 fc_fca_error(int fc_errno, char **errmsg)
2051 2051 {
2052 2052 return (fctl_error(fc_errno, errmsg));
2053 2053 }
2054 2054
2055 2055
2056 2056 int
2057 2057 fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
2058 2058 char **action, char **expln)
2059 2059 {
2060 2060 return (fctl_pkt_error(pkt, state, reason, action, expln));
2061 2061 }
2062 2062
2063 2063
2064 2064 /*
2065 2065 * WWN to string goodie. Unpredictable results will happen
2066 2066 * if enough memory isn't supplied in str argument. If you
2067 2067 * are wondering how much does this routine need, it is just
2068 2068 * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
2069 2069 * argument should have atleast 17 bytes allocated.
2070 2070 */
2071 2071 void
2072 2072 fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
2073 2073 {
2074 2074 int count;
2075 2075
2076 2076 for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
2077 2077 (void) sprintf(str, "%02x", wwn->raw_wwn[count]);
2078 2078 }
2079 2079 *str = '\0';
2080 2080 }
2081 2081
2082 2082 #define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : \
2083 2083 ((x) >= 'a' && (x) <= 'f') ? \
2084 2084 ((x) - 'a' + 10) : ((x) - 'A' + 10))
2085 2085
2086 2086 void
2087 2087 fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
2088 2088 {
2089 2089 int count = 0;
2090 2090 uchar_t byte;
2091 2091
2092 2092 while (*str) {
2093 2093 byte = FC_ATOB(*str);
2094 2094 str++;
2095 2095 byte = byte << 4 | FC_ATOB(*str);
2096 2096 str++;
2097 2097 wwn->raw_wwn[count++] = byte;
2098 2098 }
2099 2099 }
2100 2100
2101 2101 /*
2102 2102 * FCA driver's intercepted bus control operations.
2103 2103 */
2104 2104 static int
2105 2105 fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
2106 2106 ddi_ctl_enum_t op, void *arg, void *result)
2107 2107 {
2108 2108 switch (op) {
2109 2109 case DDI_CTLOPS_REPORTDEV:
2110 2110 break;
2111 2111
2112 2112 case DDI_CTLOPS_IOMIN:
2113 2113 break;
2114 2114
2115 2115 case DDI_CTLOPS_INITCHILD:
2116 2116 return (fctl_initchild(fca_dip, (dev_info_t *)arg));
2117 2117
2118 2118 case DDI_CTLOPS_UNINITCHILD:
2119 2119 return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
2120 2120
2121 2121 default:
2122 2122 return (ddi_ctlops(fca_dip, rip, op, arg, result));
2123 2123 }
2124 2124
2125 2125 return (DDI_SUCCESS);
2126 2126 }
2127 2127
2128 2128
2129 2129 /*
2130 2130 * FCAs indicate the maximum number of ports supported in their
2131 2131 * tran structure. Fail the INITCHILD if the child port number
2132 2132 * is any greater than the maximum number of ports supported
2133 2133 * by the FCA.
2134 2134 */
2135 2135 static int
2136 2136 fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2137 2137 {
2138 2138 int rval;
2139 2139 int port_no;
2140 2140 int port_len;
2141 2141 char name[20];
2142 2142 fc_fca_tran_t *tran;
2143 2143 dev_info_t *dip;
2144 2144 int portprop;
2145 2145
2146 2146 port_len = sizeof (port_no);
2147 2147
2148 2148 /* physical port do not has this property */
2149 2149 portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
2150 2150 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2151 2151 "phyport-instance", -1);
2152 2152
2153 2153 if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
2154 2154 /*
2155 2155 * Clear any addr bindings created by fcode interpreter
2156 2156 * in devi_last_addr so that a ndi_devi_find should never
2157 2157 * return this fcode node.
2158 2158 */
2159 2159 ddi_set_name_addr(port_dip, NULL);
2160 2160 return (DDI_FAILURE);
2161 2161 }
2162 2162
2163 2163 rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
2164 2164 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
2165 2165 (caddr_t)&port_no, &port_len);
2166 2166
2167 2167 if (rval != DDI_SUCCESS) {
2168 2168 return (DDI_FAILURE);
2169 2169 }
2170 2170
2171 2171 tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
2172 2172 ASSERT(tran != NULL);
2173 2173
2174 2174 (void) sprintf((char *)name, "%x,0", port_no);
2175 2175 ddi_set_name_addr(port_dip, name);
2176 2176
2177 2177 dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2178 2178
2179 2179 /*
2180 2180 * Even though we never initialize FCode nodes of fp, such a node
2181 2181 * could still be there after a DR operation. There will only be
2182 2182 * one FCode node, so if this is the one, clear it and issue a
2183 2183 * ndi_devi_find again.
2184 2184 */
2185 2185 if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
2186 2186 ddi_set_name_addr(dip, NULL);
2187 2187 dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2188 2188 }
2189 2189
2190 2190 if ((portprop == -1) && dip && (dip != port_dip)) {
2191 2191 /*
2192 2192 * Here we have a duplicate .conf entry. Clear the addr
2193 2193 * set previously and return failure.
2194 2194 */
2195 2195 ddi_set_name_addr(port_dip, NULL);
2196 2196 return (DDI_FAILURE);
2197 2197 }
2198 2198
2199 2199 return (DDI_SUCCESS);
2200 2200 }
2201 2201
2202 2202
2203 2203 /* ARGSUSED */
2204 2204 static int
2205 2205 fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2206 2206 {
2207 2207 ddi_set_name_addr(port_dip, NULL);
2208 2208 return (DDI_SUCCESS);
2209 2209 }
2210 2210
2211 2211
2212 2212 static dev_info_t *
2213 2213 fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
2214 2214 {
2215 2215 dev_info_t *dip;
2216 2216 char *addr;
2217 2217
2218 2218 ASSERT(cname != NULL && caddr != NULL);
2219 2219 /* ASSERT(DEVI_BUSY_OWNED(pdip)); */
2220 2220
2221 2221 for (dip = ddi_get_child(pdip); dip != NULL;
2222 2222 dip = ddi_get_next_sibling(dip)) {
2223 2223 if (strcmp(cname, ddi_node_name(dip)) != 0) {
2224 2224 continue;
2225 2225 }
2226 2226
2227 2227 if ((addr = ddi_get_name_addr(dip)) == NULL) {
2228 2228 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
2229 2229 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2230 2230 "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2231 2231 if (strcmp(caddr, addr) == 0) {
2232 2232 ddi_prop_free(addr);
2233 2233 return (dip);
2234 2234 }
2235 2235 ddi_prop_free(addr);
2236 2236 }
2237 2237 } else {
2238 2238 if (strcmp(caddr, addr) == 0) {
2239 2239 return (dip);
2240 2240 }
2241 2241 }
2242 2242 }
2243 2243
2244 2244 return (NULL);
2245 2245 }
2246 2246
2247 2247 int
2248 2248 fctl_check_npiv_portindex(dev_info_t *dip, int vindex)
2249 2249 {
2250 2250 int i, instance;
2251 2251 fc_local_port_t *port;
2252 2252
2253 2253 instance = ddi_get_instance(dip);
2254 2254 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2255 2255 if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
2256 2256 return (0);
2257 2257 }
2258 2258
2259 2259 i = vindex-1;
2260 2260 mutex_enter(&port->fp_mutex);
2261 2261 if (port->fp_npiv_portindex[i] == 0) {
2262 2262 mutex_exit(&port->fp_mutex);
2263 2263 return (vindex);
2264 2264 }
2265 2265 mutex_exit(&port->fp_mutex);
2266 2266 return (0);
2267 2267 }
2268 2268
2269 2269 int
2270 2270 fctl_get_npiv_portindex(dev_info_t *dip)
2271 2271 {
2272 2272 int i, instance;
2273 2273 fc_local_port_t *port;
2274 2274
2275 2275 instance = ddi_get_instance(dip);
2276 2276 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2277 2277 if (!port) {
2278 2278 return (0);
2279 2279 }
2280 2280
2281 2281 mutex_enter(&port->fp_mutex);
2282 2282 for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
2283 2283 if (port->fp_npiv_portindex[i] == 0) {
2284 2284 mutex_exit(&port->fp_mutex);
2285 2285 return (i+1);
2286 2286 }
2287 2287 }
2288 2288 mutex_exit(&port->fp_mutex);
2289 2289 return (0);
2290 2290 }
2291 2291
2292 2292
2293 2293 void
2294 2294 fctl_set_npiv_portindex(dev_info_t *dip, int index)
2295 2295 {
2296 2296 int instance;
2297 2297 fc_local_port_t *port;
2298 2298
2299 2299 instance = ddi_get_instance(dip);
2300 2300 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2301 2301 if (!port) {
2302 2302 return;
2303 2303 }
2304 2304 mutex_enter(&port->fp_mutex);
2305 2305 port->fp_npiv_portindex[index - 1] = 1;
2306 2306 mutex_exit(&port->fp_mutex);
2307 2307 }
2308 2308
2309 2309
2310 2310 int
2311 2311 fctl_fca_create_npivport(dev_info_t *parent,
2312 2312 dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
2313 2313 {
2314 2314 int rval = 0, devstrlen;
2315 2315 char *devname, *cname, *caddr, *devstr;
2316 2316 dev_info_t *child = NULL;
2317 2317 int portnum;
2318 2318
2319 2319 if (*vindex == 0) {
2320 2320 portnum = fctl_get_npiv_portindex(phydip);
2321 2321 *vindex = portnum;
2322 2322 } else {
2323 2323 portnum = fctl_check_npiv_portindex(phydip, *vindex);
2324 2324 }
2325 2325
2326 2326 if (portnum == 0) {
2327 2327 cmn_err(CE_WARN,
2328 2328 "Cann't find valid port index, fail to create devnode");
2329 2329 return (NDI_FAILURE);
2330 2330 }
2331 2331
2332 2332 devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2333 2333 (void) sprintf(devname, "fp@%x,0", portnum);
2334 2334 devstrlen = strlen(devname) + 1;
2335 2335 devstr = i_ddi_strdup(devname, KM_SLEEP);
2336 2336 i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2337 2337
2338 2338 if (fctl_findchild(parent, cname, caddr) != NULL) {
2339 2339 rval = NDI_FAILURE;
2340 2340 goto freememory;
2341 2341 }
2342 2342
2343 2343 ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
2344 2344 if (child == NULL) {
2345 2345 cmn_err(CE_WARN,
2346 2346 "fctl_create_npiv_port fail to create new devinfo");
2347 2347 rval = NDI_FAILURE;
2348 2348 goto freememory;
2349 2349 }
2350 2350
2351 2351 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2352 2352 "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2353 2353 cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
2354 2354 ddi_get_instance(parent), cname, caddr);
2355 2355 (void) ndi_devi_free(child);
2356 2356 rval = NDI_FAILURE;
2357 2357 goto freememory;
2358 2358 }
2359 2359
2360 2360 if (strlen(nname) != 0) {
2361 2361 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2362 2362 "node-name", nname) != DDI_PROP_SUCCESS) {
2363 2363 (void) ndi_devi_free(child);
2364 2364 rval = NDI_FAILURE;
2365 2365 goto freememory;
2366 2366 }
2367 2367 }
2368 2368
2369 2369 if (strlen(pname) != 0) {
2370 2370 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2371 2371 "port-name", pname) != DDI_PROP_SUCCESS) {
2372 2372 (void) ndi_devi_free(child);
2373 2373 rval = NDI_FAILURE;
2374 2374 goto freememory;
2375 2375 }
2376 2376 }
2377 2377
2378 2378 if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2379 2379 "port", portnum) != DDI_PROP_SUCCESS) {
2380 2380 cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
2381 2381 ddi_get_instance(parent), cname, caddr);
2382 2382 (void) ndi_devi_free(child);
2383 2383 rval = NDI_FAILURE;
2384 2384 goto freememory;
2385 2385 }
2386 2386
2387 2387 if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2388 2388 "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
2389 2389 cmn_err(CE_WARN,
2390 2390 "fp%d: prop_update phyport-instance %s@%s failed",
2391 2391 ddi_get_instance(parent), cname, caddr);
2392 2392 (void) ndi_devi_free(child);
2393 2393 rval = NDI_FAILURE;
2394 2394 goto freememory;
2395 2395 }
2396 2396
2397 2397 rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
2398 2398 if (rval != NDI_SUCCESS) {
2399 2399 cmn_err(CE_WARN, "fp%d: online_driver %s failed",
2400 2400 ddi_get_instance(parent), cname);
2401 2401 rval = NDI_FAILURE;
2402 2402 goto freememory;
2403 2403 }
2404 2404
2405 2405 fctl_set_npiv_portindex(phydip, portnum);
2406 2406 freememory:
2407 2407 kmem_free(devstr, devstrlen);
2408 2408 kmem_free(devname, MAXNAMELEN);
2409 2409
2410 2410 return (rval);
2411 2411 }
2412 2412
2413 2413
2414 2414 void
2415 2415 fctl_add_port(fc_local_port_t *port)
2416 2416 {
2417 2417 fc_fca_port_t *new;
2418 2418
2419 2419 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2420 2420
2421 2421 mutex_enter(&fctl_port_lock);
2422 2422 new->port_handle = port;
2423 2423 new->port_next = fctl_fca_portlist;
2424 2424 fctl_fca_portlist = new;
2425 2425 mutex_exit(&fctl_port_lock);
2426 2426 }
2427 2427
2428 2428
2429 2429 void
2430 2430 fctl_remove_port(fc_local_port_t *port)
2431 2431 {
2432 2432 fc_ulp_module_t *mod;
2433 2433 fc_fca_port_t *prev;
2434 2434 fc_fca_port_t *list;
2435 2435 fc_ulp_ports_t *ulp_port;
2436 2436
2437 2437 rw_enter(&fctl_ulp_lock, RW_WRITER);
2438 2438 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2439 2439
2440 2440 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2441 2441 ulp_port = fctl_get_ulp_port(mod, port);
2442 2442 if (ulp_port == NULL) {
2443 2443 continue;
2444 2444 }
2445 2445
2446 2446 #ifndef __lock_lint
2447 2447 ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2448 2448 #endif /* __lock_lint */
2449 2449
2450 2450 (void) fctl_remove_ulp_port(mod, port);
2451 2451 }
2452 2452
2453 2453 rw_exit(&fctl_mod_ports_lock);
2454 2454 rw_exit(&fctl_ulp_lock);
2455 2455
2456 2456 mutex_enter(&fctl_port_lock);
2457 2457
2458 2458 list = fctl_fca_portlist;
2459 2459 prev = NULL;
2460 2460 while (list != NULL) {
2461 2461 if (list->port_handle == port) {
2462 2462 if (prev == NULL) {
2463 2463 fctl_fca_portlist = list->port_next;
2464 2464 } else {
2465 2465 prev->port_next = list->port_next;
2466 2466 }
2467 2467 kmem_free(list, sizeof (*list));
2468 2468 break;
2469 2469 }
2470 2470 prev = list;
2471 2471 list = list->port_next;
2472 2472 }
2473 2473 mutex_exit(&fctl_port_lock);
2474 2474 }
2475 2475
2476 2476
2477 2477 void
2478 2478 fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
2479 2479 struct modlinkage *linkage)
2480 2480 {
2481 2481 int rval;
2482 2482 uint32_t s_id;
2483 2483 uint32_t state;
2484 2484 fc_ulp_module_t *mod;
2485 2485 fc_ulp_port_info_t info;
2486 2486 fc_ulp_ports_t *ulp_port;
2487 2487
2488 2488 ASSERT(!MUTEX_HELD(&port->fp_mutex));
2489 2489
2490 2490 info.port_linkage = linkage;
2491 2491 info.port_dip = port->fp_port_dip;
2492 2492 info.port_handle = (opaque_t)port;
2493 2493 info.port_dma_behavior = port->fp_dma_behavior;
2494 2494 info.port_fcp_dma = port->fp_fcp_dma;
2495 2495 info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2496 2496 info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2497 2497 info.port_reset_action = port->fp_reset_action;
2498 2498
2499 2499 mutex_enter(&port->fp_mutex);
2500 2500
2501 2501 /*
2502 2502 * It is still possible that another thread could have gotten
2503 2503 * into the detach process before we got here.
2504 2504 */
2505 2505 if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
2506 2506 mutex_exit(&port->fp_mutex);
2507 2507 return;
2508 2508 }
2509 2509
2510 2510 s_id = port->fp_port_id.port_id;
2511 2511 if (port->fp_statec_busy) {
2512 2512 info.port_state = port->fp_bind_state;
2513 2513 } else {
2514 2514 info.port_state = port->fp_state;
2515 2515 }
2516 2516
2517 2517 switch (state = FC_PORT_STATE_MASK(info.port_state)) {
2518 2518 case FC_STATE_LOOP:
2519 2519 case FC_STATE_NAMESERVICE:
2520 2520 info.port_state &= ~state;
2521 2521 info.port_state |= FC_STATE_ONLINE;
2522 2522 break;
2523 2523
2524 2524 default:
2525 2525 break;
2526 2526 }
2527 2527 ASSERT((info.port_state & FC_STATE_LOOP) == 0);
2528 2528
2529 2529 info.port_flags = port->fp_topology;
2530 2530 info.port_pwwn = port->fp_service_params.nport_ww_name;
2531 2531 info.port_nwwn = port->fp_service_params.node_ww_name;
2532 2532 mutex_exit(&port->fp_mutex);
2533 2533
2534 2534 rw_enter(&fctl_ulp_lock, RW_READER);
2535 2535 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2536 2536
2537 2537 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2538 2538 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2539 2539 (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2540 2540 /*
2541 2541 * We don't support IP over FC on FCOE HBA
2542 2542 */
2543 2543 continue;
2544 2544 }
2545 2545
2546 2546 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2547 2547 ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
2548 2548 ASSERT(ulp_port != NULL);
2549 2549
2550 2550 mutex_enter(&ulp_port->port_mutex);
2551 2551 ulp_port->port_statec = ((info.port_state &
2552 2552 FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
2553 2553 FC_ULP_STATEC_OFFLINE);
2554 2554 mutex_exit(&ulp_port->port_mutex);
2555 2555 }
2556 2556 }
2557 2557
2558 2558 rw_downgrade(&fctl_mod_ports_lock);
2559 2559
2560 2560 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2561 2561 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2562 2562 (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2563 2563 /*
2564 2564 * We don't support IP over FC on FCOE HBA
2565 2565 */
2566 2566 continue;
2567 2567 }
2568 2568
2569 2569 ulp_port = fctl_get_ulp_port(mod, port);
2570 2570 ASSERT(ulp_port != NULL);
2571 2571
2572 2572 if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
2573 2573 continue;
2574 2574 }
2575 2575
2576 2576 fctl_init_dma_attr(port, mod, &info);
2577 2577
2578 2578 rval = mod->mod_info->ulp_port_attach(
2579 2579 mod->mod_info->ulp_handle, &info, cmd, s_id);
2580 2580
2581 2581 fctl_post_attach(mod, ulp_port, cmd, rval);
2582 2582
2583 2583 if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
2584 2584 strcmp(mod->mod_info->ulp_name, "fcp") == 0) {
2585 2585 ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
2586 2586 }
2587 2587 }
2588 2588
2589 2589 rw_exit(&fctl_mod_ports_lock);
2590 2590 rw_exit(&fctl_ulp_lock);
2591 2591 }
2592 2592
2593 2593
2594 2594 static int
2595 2595 fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
2596 2596 {
2597 2597 int rval = FC_SUCCESS;
2598 2598
2599 2599 mutex_enter(&ulp_port->port_mutex);
2600 2600
2601 2601 switch (cmd) {
2602 2602 case FC_CMD_ATTACH:
2603 2603 if (ulp_port->port_dstate & ULP_PORT_ATTACH) {
2604 2604 rval = FC_FAILURE;
2605 2605 }
2606 2606 break;
2607 2607
2608 2608 case FC_CMD_RESUME:
2609 2609 ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
2610 2610 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2611 2611 !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) {
2612 2612 rval = FC_FAILURE;
2613 2613 }
2614 2614 break;
2615 2615
2616 2616 case FC_CMD_POWER_UP:
2617 2617 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2618 2618 !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
2619 2619 rval = FC_FAILURE;
2620 2620 }
2621 2621 break;
2622 2622 }
2623 2623
2624 2624 if (rval == FC_SUCCESS) {
2625 2625 ulp_port->port_dstate |= ULP_PORT_BUSY;
2626 2626 }
2627 2627 mutex_exit(&ulp_port->port_mutex);
2628 2628
2629 2629 return (rval);
2630 2630 }
2631 2631
2632 2632
2633 2633 static void
2634 2634 fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2635 2635 fc_attach_cmd_t cmd, int rval)
2636 2636 {
2637 2637 int be_chatty;
2638 2638
2639 2639 ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
2640 2640 cmd == FC_CMD_POWER_UP);
2641 2641
2642 2642 mutex_enter(&ulp_port->port_mutex);
2643 2643 ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2644 2644
2645 2645 be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1;
2646 2646
2647 2647 if (rval != FC_SUCCESS) {
2648 2648 caddr_t op;
2649 2649 fc_local_port_t *port = ulp_port->port_handle;
2650 2650
2651 2651 mutex_exit(&ulp_port->port_mutex);
2652 2652
2653 2653 switch (cmd) {
2654 2654 case FC_CMD_ATTACH:
2655 2655 op = "attach";
2656 2656 break;
2657 2657
2658 2658 case FC_CMD_RESUME:
2659 2659 op = "resume";
2660 2660 break;
2661 2661
2662 2662 case FC_CMD_POWER_UP:
2663 2663 op = "power up";
2664 2664 break;
2665 2665 }
2666 2666
2667 2667 if (be_chatty) {
2668 2668 cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2669 2669 port->fp_instance, op, mod->mod_info->ulp_name);
2670 2670 }
2671 2671
2672 2672 return;
2673 2673 }
2674 2674
2675 2675 switch (cmd) {
2676 2676 case FC_CMD_ATTACH:
2677 2677 ulp_port->port_dstate |= ULP_PORT_ATTACH;
2678 2678 break;
2679 2679
2680 2680 case FC_CMD_RESUME:
2681 2681 ulp_port->port_dstate &= ~ULP_PORT_SUSPEND;
2682 2682 break;
2683 2683
2684 2684 case FC_CMD_POWER_UP:
2685 2685 ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN;
2686 2686 break;
2687 2687 }
2688 2688 mutex_exit(&ulp_port->port_mutex);
2689 2689 }
2690 2690
2691 2691
2692 2692 int
2693 2693 fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
2694 2694 struct modlinkage *linkage)
2695 2695 {
2696 2696 int rval = FC_SUCCESS;
2697 2697 fc_ulp_module_t *mod;
2698 2698 fc_ulp_port_info_t info;
2699 2699 fc_ulp_ports_t *ulp_port;
2700 2700
2701 2701 ASSERT(!MUTEX_HELD(&port->fp_mutex));
2702 2702
2703 2703 info.port_linkage = linkage;
2704 2704 info.port_dip = port->fp_port_dip;
2705 2705 info.port_handle = (opaque_t)port;
2706 2706 info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2707 2707 info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2708 2708
2709 2709 rw_enter(&fctl_ulp_lock, RW_READER);
2710 2710 rw_enter(&fctl_mod_ports_lock, RW_READER);
2711 2711
2712 2712 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2713 2713 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2714 2714 continue;
2715 2715 }
2716 2716
2717 2717 if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
2718 2718 continue;
2719 2719 }
2720 2720
2721 2721 fctl_init_dma_attr(port, mod, &info);
2722 2722
2723 2723 rval = mod->mod_info->ulp_port_detach(
2724 2724 mod->mod_info->ulp_handle, &info, cmd);
2725 2725
2726 2726 fctl_post_detach(mod, ulp_port, cmd, rval);
2727 2727
2728 2728 if (rval != FC_SUCCESS) {
2729 2729 break;
2730 2730 }
2731 2731
2732 2732 if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
2733 2733 "fcp") == 0) {
2734 2734 ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
2735 2735 }
2736 2736
2737 2737 mutex_enter(&ulp_port->port_mutex);
2738 2738 ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE;
2739 2739 mutex_exit(&ulp_port->port_mutex);
2740 2740 }
2741 2741
2742 2742 rw_exit(&fctl_mod_ports_lock);
2743 2743 rw_exit(&fctl_ulp_lock);
2744 2744
2745 2745 return (rval);
2746 2746 }
2747 2747
2748 2748 static void
2749 2749 fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
2750 2750 fc_ulp_port_info_t *info)
2751 2751 {
2752 2752
2753 2753 if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
2754 2754 (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
2755 2755 info->port_cmd_dma_attr =
2756 2756 port->fp_fca_tran->fca_dma_fcp_cmd_attr;
2757 2757 info->port_data_dma_attr =
2758 2758 port->fp_fca_tran->fca_dma_fcp_data_attr;
2759 2759 info->port_resp_dma_attr =
2760 2760 port->fp_fca_tran->fca_dma_fcp_rsp_attr;
2761 2761 } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
2762 2762 info->port_cmd_dma_attr =
2763 2763 port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
2764 2764 info->port_data_dma_attr =
2765 2765 port->fp_fca_tran->fca_dma_attr;
2766 2766 info->port_resp_dma_attr =
2767 2767 port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
2768 2768 } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
2769 2769 info->port_cmd_dma_attr =
2770 2770 port->fp_fca_tran->fca_dma_fcip_cmd_attr;
2771 2771 info->port_data_dma_attr =
2772 2772 port->fp_fca_tran->fca_dma_attr;
2773 2773 info->port_resp_dma_attr =
2774 2774 port->fp_fca_tran->fca_dma_fcip_rsp_attr;
2775 2775 } else {
2776 2776 info->port_cmd_dma_attr = info->port_data_dma_attr =
2777 2777 info->port_resp_dma_attr =
2778 2778 port->fp_fca_tran->fca_dma_attr; /* default */
2779 2779 }
2780 2780 }
2781 2781
2782 2782 static int
2783 2783 fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
2784 2784 {
2785 2785 int rval = FC_SUCCESS;
2786 2786
2787 2787 mutex_enter(&ulp_port->port_mutex);
2788 2788
2789 2789 switch (cmd) {
2790 2790 case FC_CMD_DETACH:
2791 2791 if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
2792 2792 rval = FC_FAILURE;
2793 2793 }
2794 2794 break;
2795 2795
2796 2796 case FC_CMD_SUSPEND:
2797 2797 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2798 2798 ulp_port->port_dstate & ULP_PORT_SUSPEND) {
2799 2799 rval = FC_FAILURE;
2800 2800 }
2801 2801 break;
2802 2802
2803 2803 case FC_CMD_POWER_DOWN:
2804 2804 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2805 2805 ulp_port->port_dstate & ULP_PORT_POWER_DOWN) {
2806 2806 rval = FC_FAILURE;
2807 2807 }
2808 2808 break;
2809 2809 }
2810 2810
2811 2811 if (rval == FC_SUCCESS) {
2812 2812 ulp_port->port_dstate |= ULP_PORT_BUSY;
2813 2813 }
2814 2814 mutex_exit(&ulp_port->port_mutex);
2815 2815
2816 2816 return (rval);
2817 2817 }
2818 2818
2819 2819
2820 2820 static void
2821 2821 fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2822 2822 fc_detach_cmd_t cmd, int rval)
2823 2823 {
2824 2824 ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
2825 2825 cmd == FC_CMD_POWER_DOWN);
2826 2826
2827 2827 mutex_enter(&ulp_port->port_mutex);
2828 2828 ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2829 2829
2830 2830 if (rval != FC_SUCCESS) {
2831 2831 caddr_t op;
2832 2832 fc_local_port_t *port = ulp_port->port_handle;
2833 2833
2834 2834 mutex_exit(&ulp_port->port_mutex);
2835 2835
2836 2836 switch (cmd) {
2837 2837 case FC_CMD_DETACH:
2838 2838 op = "detach";
2839 2839 break;
2840 2840
2841 2841 case FC_CMD_SUSPEND:
2842 2842 op = "suspend";
2843 2843 break;
2844 2844
2845 2845 case FC_CMD_POWER_DOWN:
2846 2846 op = "power down";
2847 2847 break;
2848 2848 }
2849 2849
2850 2850 cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2851 2851 port->fp_instance, op, mod->mod_info->ulp_name);
2852 2852
2853 2853 return;
2854 2854 }
2855 2855
2856 2856 switch (cmd) {
2857 2857 case FC_CMD_DETACH:
2858 2858 ulp_port->port_dstate &= ~ULP_PORT_ATTACH;
2859 2859 break;
2860 2860
2861 2861 case FC_CMD_SUSPEND:
2862 2862 ulp_port->port_dstate |= ULP_PORT_SUSPEND;
2863 2863 break;
2864 2864
2865 2865 case FC_CMD_POWER_DOWN:
2866 2866 ulp_port->port_dstate |= ULP_PORT_POWER_DOWN;
2867 2867 break;
2868 2868 }
2869 2869 mutex_exit(&ulp_port->port_mutex);
2870 2870 }
2871 2871
2872 2872
2873 2873 static fc_ulp_ports_t *
2874 2874 fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
2875 2875 int sleep)
2876 2876 {
2877 2877 fc_ulp_ports_t *last;
2878 2878 fc_ulp_ports_t *next;
2879 2879 fc_ulp_ports_t *new;
2880 2880
2881 2881 ASSERT(RW_READ_HELD(&fctl_ulp_lock));
2882 2882 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2883 2883
2884 2884 last = NULL;
2885 2885 next = ulp_module->mod_ports;
2886 2886
2887 2887 while (next != NULL) {
2888 2888 last = next;
2889 2889 next = next->port_next;
2890 2890 }
2891 2891
2892 2892 new = fctl_alloc_ulp_port(sleep);
2893 2893 if (new == NULL) {
2894 2894 return (new);
2895 2895 }
2896 2896
2897 2897 new->port_handle = port_handle;
2898 2898 if (last == NULL) {
2899 2899 ulp_module->mod_ports = new;
2900 2900 } else {
2901 2901 last->port_next = new;
2902 2902 }
2903 2903
2904 2904 return (new);
2905 2905 }
2906 2906
2907 2907
2908 2908 static fc_ulp_ports_t *
2909 2909 fctl_alloc_ulp_port(int sleep)
2910 2910 {
2911 2911 fc_ulp_ports_t *new;
2912 2912
2913 2913 new = kmem_zalloc(sizeof (*new), sleep);
2914 2914 if (new == NULL) {
2915 2915 return (new);
2916 2916 }
2917 2917 mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
2918 2918
2919 2919 return (new);
2920 2920 }
2921 2921
2922 2922
2923 2923 static int
2924 2924 fctl_remove_ulp_port(struct ulp_module *ulp_module,
2925 2925 fc_local_port_t *port_handle)
2926 2926 {
2927 2927 fc_ulp_ports_t *last;
2928 2928 fc_ulp_ports_t *next;
2929 2929
2930 2930 ASSERT(RW_WRITE_HELD(&fctl_ulp_lock));
2931 2931 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2932 2932
2933 2933 last = NULL;
2934 2934 next = ulp_module->mod_ports;
2935 2935
2936 2936 while (next != NULL) {
2937 2937 if (next->port_handle == port_handle) {
2938 2938 if (next->port_dstate & ULP_PORT_ATTACH) {
2939 2939 return (FC_FAILURE);
2940 2940 }
2941 2941 break;
2942 2942 }
2943 2943 last = next;
2944 2944 next = next->port_next;
2945 2945 }
2946 2946
2947 2947 if (next != NULL) {
2948 2948 ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
2949 2949
2950 2950 if (last == NULL) {
2951 2951 ulp_module->mod_ports = next->port_next;
2952 2952 } else {
2953 2953 last->port_next = next->port_next;
2954 2954 }
2955 2955 fctl_dealloc_ulp_port(next);
2956 2956
2957 2957 return (FC_SUCCESS);
2958 2958 } else {
2959 2959 return (FC_FAILURE);
2960 2960 }
2961 2961 }
2962 2962
2963 2963
2964 2964 static void
2965 2965 fctl_dealloc_ulp_port(fc_ulp_ports_t *next)
2966 2966 {
2967 2967 mutex_destroy(&next->port_mutex);
2968 2968 kmem_free(next, sizeof (*next));
2969 2969 }
2970 2970
2971 2971
2972 2972 static fc_ulp_ports_t *
2973 2973 fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
2974 2974 {
2975 2975 fc_ulp_ports_t *next;
2976 2976
2977 2977 ASSERT(RW_LOCK_HELD(&fctl_ulp_lock));
2978 2978 ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock));
2979 2979
2980 2980 for (next = ulp_module->mod_ports; next != NULL;
2981 2981 next = next->port_next) {
2982 2982 if (next->port_handle == port_handle) {
2983 2983 return (next);
2984 2984 }
2985 2985 }
2986 2986
2987 2987 return (NULL);
2988 2988 }
2989 2989
2990 2990
2991 2991 /*
2992 2992 * Pass state change notfications on to registered ULPs.
2993 2993 *
2994 2994 * Can issue wakeups to client callers who might be waiting for completions
2995 2995 * on other threads.
2996 2996 *
2997 2997 * Caution: will silently deallocate any fc_remote_port_t and/or
2998 2998 * fc_remote_node_t structs it finds that are not in use.
2999 2999 */
3000 3000 void
3001 3001 fctl_ulp_statec_cb(void *arg)
3002 3002 {
3003 3003 uint32_t s_id;
3004 3004 uint32_t new_state;
3005 3005 fc_local_port_t *port;
3006 3006 fc_ulp_ports_t *ulp_port;
3007 3007 fc_ulp_module_t *mod;
3008 3008 fc_port_clist_t *clist = (fc_port_clist_t *)arg;
3009 3009
3010 3010 ASSERT(clist != NULL);
3011 3011
3012 3012 port = clist->clist_port;
3013 3013
3014 3014 mutex_enter(&port->fp_mutex);
3015 3015 s_id = port->fp_port_id.port_id;
3016 3016 mutex_exit(&port->fp_mutex);
3017 3017
3018 3018 switch (clist->clist_state) {
3019 3019 case FC_STATE_ONLINE:
3020 3020 new_state = FC_ULP_STATEC_ONLINE;
3021 3021 break;
3022 3022
3023 3023 case FC_STATE_OFFLINE:
3024 3024 if (clist->clist_len) {
3025 3025 new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT;
3026 3026 } else {
3027 3027 new_state = FC_ULP_STATEC_OFFLINE;
3028 3028 }
3029 3029 break;
3030 3030
3031 3031 default:
3032 3032 new_state = FC_ULP_STATEC_DONT_CARE;
3033 3033 break;
3034 3034 }
3035 3035
3036 3036 #ifdef DEBUG
3037 3037 /*
3038 3038 * sanity check for presence of OLD devices in the hash lists
3039 3039 */
3040 3040 if (clist->clist_size) {
3041 3041 int count;
3042 3042 fc_remote_port_t *pd;
3043 3043
3044 3044 ASSERT(clist->clist_map != NULL);
3045 3045 for (count = 0; count < clist->clist_len; count++) {
3046 3046 if (clist->clist_map[count].map_state ==
3047 3047 PORT_DEVICE_INVALID) {
3048 3048 la_wwn_t pwwn;
3049 3049 fc_portid_t d_id;
3050 3050
3051 3051 pd = clist->clist_map[count].map_pd;
3052 3052 if (pd != NULL) {
3053 3053 mutex_enter(&pd->pd_mutex);
3054 3054 pwwn = pd->pd_port_name;
3055 3055 d_id = pd->pd_port_id;
3056 3056 mutex_exit(&pd->pd_mutex);
3057 3057
3058 3058 pd = fctl_get_remote_port_by_pwwn(port,
3059 3059 &pwwn);
3060 3060
3061 3061 ASSERT(pd != clist->clist_map[count].
3062 3062 map_pd);
3063 3063
3064 3064 pd = fctl_get_remote_port_by_did(port,
3065 3065 d_id.port_id);
3066 3066 ASSERT(pd != clist->clist_map[count].
3067 3067 map_pd);
3068 3068 }
3069 3069 }
3070 3070 }
3071 3071 }
3072 3072 #endif
3073 3073
3074 3074 /*
3075 3075 * Check for duplicate map entries
3076 3076 */
3077 3077 if (clist->clist_size) {
3078 3078 int count;
3079 3079 fc_remote_port_t *pd1, *pd2;
3080 3080
3081 3081 ASSERT(clist->clist_map != NULL);
3082 3082 for (count = 0; count < clist->clist_len-1; count++) {
3083 3083 int count2;
3084 3084
3085 3085 pd1 = clist->clist_map[count].map_pd;
3086 3086 if (pd1 == NULL) {
3087 3087 continue;
3088 3088 }
3089 3089
3090 3090 for (count2 = count+1;
3091 3091 count2 < clist->clist_len;
3092 3092 count2++) {
3093 3093
3094 3094 pd2 = clist->clist_map[count2].map_pd;
3095 3095 if (pd2 == NULL) {
3096 3096 continue;
3097 3097 }
3098 3098
3099 3099 if (pd1 == pd2) {
3100 3100 clist->clist_map[count].map_flags |=
3101 3101 PORT_DEVICE_DUPLICATE_MAP_ENTRY;
3102 3102 break;
3103 3103 }
3104 3104 }
3105 3105 }
3106 3106 }
3107 3107
3108 3108
3109 3109 rw_enter(&fctl_ulp_lock, RW_READER);
3110 3110 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
3111 3111 rw_enter(&fctl_mod_ports_lock, RW_READER);
3112 3112 ulp_port = fctl_get_ulp_port(mod, port);
3113 3113 rw_exit(&fctl_mod_ports_lock);
3114 3114
3115 3115 if (ulp_port == NULL) {
3116 3116 continue;
3117 3117 }
3118 3118
3119 3119 mutex_enter(&ulp_port->port_mutex);
3120 3120 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
3121 3121 mutex_exit(&ulp_port->port_mutex);
3122 3122 continue;
3123 3123 }
3124 3124
3125 3125 switch (ulp_port->port_statec) {
3126 3126 case FC_ULP_STATEC_DONT_CARE:
3127 3127 if (ulp_port->port_statec != new_state) {
3128 3128 ulp_port->port_statec = new_state;
3129 3129 }
3130 3130 break;
3131 3131
3132 3132 case FC_ULP_STATEC_ONLINE:
3133 3133 case FC_ULP_STATEC_OFFLINE:
3134 3134 if (ulp_port->port_statec == new_state) {
3135 3135 mutex_exit(&ulp_port->port_mutex);
3136 3136 continue;
3137 3137 }
3138 3138 ulp_port->port_statec = new_state;
3139 3139 break;
3140 3140
3141 3141 case FC_ULP_STATEC_OFFLINE_TIMEOUT:
3142 3142 if (ulp_port->port_statec == new_state ||
3143 3143 new_state == FC_ULP_STATEC_OFFLINE) {
3144 3144 mutex_exit(&ulp_port->port_mutex);
3145 3145 continue;
3146 3146 }
3147 3147 ulp_port->port_statec = new_state;
3148 3148 break;
3149 3149
3150 3150 default:
3151 3151 ASSERT(0);
3152 3152 break;
3153 3153 }
3154 3154
3155 3155 mod->mod_info->ulp_statec_callback(
3156 3156 mod->mod_info->ulp_handle, (opaque_t)port,
3157 3157 clist->clist_state, clist->clist_flags,
3158 3158 clist->clist_map, clist->clist_len, s_id);
3159 3159
3160 3160 mutex_exit(&ulp_port->port_mutex);
3161 3161 }
3162 3162 rw_exit(&fctl_ulp_lock);
3163 3163
3164 3164 if (clist->clist_size) {
3165 3165 int count;
3166 3166 fc_remote_node_t *node;
3167 3167 fc_remote_port_t *pd;
3168 3168
3169 3169 ASSERT(clist->clist_map != NULL);
3170 3170 for (count = 0; count < clist->clist_len; count++) {
3171 3171
3172 3172 if ((pd = clist->clist_map[count].map_pd) == NULL) {
3173 3173 continue;
3174 3174 }
3175 3175
3176 3176 mutex_enter(&pd->pd_mutex);
3177 3177
3178 3178 pd->pd_ref_count--;
3179 3179 ASSERT(pd->pd_ref_count >= 0);
3180 3180
3181 3181 if (clist->clist_map[count].map_state !=
3182 3182 PORT_DEVICE_INVALID) {
3183 3183 mutex_exit(&pd->pd_mutex);
3184 3184 continue;
3185 3185 }
3186 3186
3187 3187 node = pd->pd_remote_nodep;
3188 3188 pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS;
3189 3189
3190 3190 mutex_exit(&pd->pd_mutex);
3191 3191
3192 3192 /*
3193 3193 * This fc_remote_port_t is no longer referenced
3194 3194 * by any ULPs. Deallocate it if its pd_ref_count
3195 3195 * has reached zero.
3196 3196 */
3197 3197 if ((fctl_destroy_remote_port(port, pd) == 0) &&
3198 3198 (node != NULL)) {
3199 3199 fctl_destroy_remote_node(node);
3200 3200 }
3201 3201 }
3202 3202
3203 3203 kmem_free(clist->clist_map,
3204 3204 sizeof (*(clist->clist_map)) * clist->clist_size);
3205 3205 }
3206 3206
3207 3207 if (clist->clist_wait) {
3208 3208 mutex_enter(&clist->clist_mutex);
3209 3209 clist->clist_wait = 0;
3210 3210 cv_signal(&clist->clist_cv);
3211 3211 mutex_exit(&clist->clist_mutex);
3212 3212 } else {
3213 3213 kmem_free(clist, sizeof (*clist));
3214 3214 }
3215 3215 }
3216 3216
3217 3217
3218 3218 /*
3219 3219 * Allocate an fc_remote_node_t struct to represent a remote node for the
3220 3220 * given nwwn. This will also add the nwwn to the global nwwn table.
3221 3221 *
3222 3222 * Returns a pointer to the newly-allocated struct. Returns NULL if
3223 3223 * the kmem_zalloc fails or if the enlist_wwn attempt fails.
3224 3224 */
3225 3225 fc_remote_node_t *
3226 3226 fctl_create_remote_node(la_wwn_t *nwwn, int sleep)
3227 3227 {
3228 3228 fc_remote_node_t *rnodep;
3229 3229
3230 3230 if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
3231 3231 return (NULL);
3232 3232 }
3233 3233
3234 3234 mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
3235 3235
3236 3236 rnodep->fd_node_name = *nwwn;
3237 3237 rnodep->fd_flags = FC_REMOTE_NODE_VALID;
3238 3238 rnodep->fd_numports = 1;
3239 3239
3240 3240 if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
3241 3241 mutex_destroy(&rnodep->fd_mutex);
3242 3242 kmem_free(rnodep, sizeof (*rnodep));
3243 3243 return (NULL);
3244 3244 }
3245 3245
3246 3246 return (rnodep);
3247 3247 }
3248 3248
3249 3249 /*
3250 3250 * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
3251 3251 * Silently skips the deconstruct/free if there are any fc_remote_port_t
3252 3252 * (remote port device) structs still referenced by the given
3253 3253 * fc_remote_node_t struct.
3254 3254 */
3255 3255 void
3256 3256 fctl_destroy_remote_node(fc_remote_node_t *rnodep)
3257 3257 {
3258 3258 mutex_enter(&rnodep->fd_mutex);
3259 3259
3260 3260 /*
3261 3261 * Look at the count and linked list of of remote ports
3262 3262 * (fc_remote_port_t structs); bail if these indicate that
3263 3263 * given fc_remote_node_t may be in use.
3264 3264 */
3265 3265 if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
3266 3266 mutex_exit(&rnodep->fd_mutex);
3267 3267 return;
3268 3268 }
3269 3269
3270 3270 mutex_exit(&rnodep->fd_mutex);
3271 3271
3272 3272 mutex_destroy(&rnodep->fd_mutex);
3273 3273 kmem_free(rnodep, sizeof (*rnodep));
3274 3274 }
3275 3275
3276 3276
3277 3277 /*
3278 3278 * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
3279 3279 * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3280 3280 * This only fails if the kmem_zalloc fails. This does not check for a
3281 3281 * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
3282 3282 * This is only called from fctl_create_remote_node().
3283 3283 */
3284 3284 int
3285 3285 fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
3286 3286 {
3287 3287 int index;
3288 3288 fctl_nwwn_elem_t *new;
3289 3289 fctl_nwwn_list_t *head;
3290 3290
3291 3291 ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3292 3292
3293 3293 if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
3294 3294 return (FC_FAILURE);
3295 3295 }
3296 3296
3297 3297 mutex_enter(&fctl_nwwn_hash_mutex);
3298 3298 new->fne_nodep = rnodep;
3299 3299
3300 3300 mutex_enter(&rnodep->fd_mutex);
3301 3301 ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
3302 3302 index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3303 3303 fctl_nwwn_table_size);
3304 3304 mutex_exit(&rnodep->fd_mutex);
3305 3305
3306 3306 head = &fctl_nwwn_hash_table[index];
3307 3307
3308 3308 /* Link it in at the head of the hash list */
3309 3309 new->fne_nextp = head->fnl_headp;
3310 3310 head->fnl_headp = new;
3311 3311
3312 3312 mutex_exit(&fctl_nwwn_hash_mutex);
3313 3313
3314 3314 return (FC_SUCCESS);
3315 3315 }
3316 3316
3317 3317
3318 3318 /*
3319 3319 * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
3320 3320 * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3321 3321 */
3322 3322 void
3323 3323 fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
3324 3324 {
3325 3325 int index;
3326 3326 fctl_nwwn_list_t *head;
3327 3327 fctl_nwwn_elem_t *elem;
3328 3328 fctl_nwwn_elem_t *prev;
3329 3329
3330 3330 ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
3331 3331 ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
3332 3332
3333 3333 index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3334 3334 fctl_nwwn_table_size);
3335 3335
3336 3336 head = &fctl_nwwn_hash_table[index];
3337 3337 elem = head->fnl_headp;
3338 3338 prev = NULL;
3339 3339
3340 3340 while (elem != NULL) {
3341 3341 if (elem->fne_nodep == rnodep) {
3342 3342 /*
3343 3343 * Found it -- unlink it from the list & decrement
3344 3344 * the count for the hash chain.
3345 3345 */
3346 3346 if (prev == NULL) {
3347 3347 head->fnl_headp = elem->fne_nextp;
3348 3348 } else {
3349 3349 prev->fne_nextp = elem->fne_nextp;
3350 3350 }
3351 3351 break;
3352 3352 }
3353 3353 prev = elem;
3354 3354 elem = elem->fne_nextp;
3355 3355 }
3356 3356
3357 3357 if (elem != NULL) {
3358 3358 kmem_free(elem, sizeof (*elem));
3359 3359 }
3360 3360 }
3361 3361
3362 3362
3363 3363 /*
3364 3364 * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3365 3365 * Looks in the global fctl_nwwn_hash_table[]. Identical to the
3366 3366 * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
3367 3367 * the fc_count reference count in the f_device_t before returning.
3368 3368 *
3369 3369 * This function is called by: fctl_create_remote_port_t().
3370 3370 *
3371 3371 * OLD COMMENT:
3372 3372 * Note: The calling thread needs to make sure it isn't holding any device
3373 3373 * mutex (more so the fc_remote_node_t that could potentially have this wwn).
3374 3374 */
3375 3375 fc_remote_node_t *
3376 3376 fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
3377 3377 {
3378 3378 int index;
3379 3379 fctl_nwwn_elem_t *elem;
3380 3380 fc_remote_node_t *next;
3381 3381 fc_remote_node_t *rnodep = NULL;
3382 3382
3383 3383 index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3384 3384 fctl_nwwn_table_size);
3385 3385 ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3386 3386
3387 3387 mutex_enter(&fctl_nwwn_hash_mutex);
3388 3388 elem = fctl_nwwn_hash_table[index].fnl_headp;
3389 3389 while (elem != NULL) {
3390 3390 next = elem->fne_nodep;
3391 3391 if (next != NULL) {
3392 3392 mutex_enter(&next->fd_mutex);
3393 3393 if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3394 3394 rnodep = next;
3395 3395 mutex_exit(&next->fd_mutex);
3396 3396 break;
3397 3397 }
3398 3398 mutex_exit(&next->fd_mutex);
3399 3399 }
3400 3400 elem = elem->fne_nextp;
3401 3401 }
3402 3402 mutex_exit(&fctl_nwwn_hash_mutex);
3403 3403
3404 3404 return (rnodep);
3405 3405 }
3406 3406
3407 3407
3408 3408 /*
3409 3409 * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3410 3410 * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
3411 3411 * reference count in the f_device_t before returning.
3412 3412 *
3413 3413 * This function is only called by fctl_create_remote_port_t().
3414 3414 */
3415 3415 fc_remote_node_t *
3416 3416 fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
3417 3417 {
3418 3418 int index;
3419 3419 fctl_nwwn_elem_t *elem;
3420 3420 fc_remote_node_t *next;
3421 3421 fc_remote_node_t *rnodep = NULL;
3422 3422
3423 3423 index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3424 3424 fctl_nwwn_table_size);
3425 3425 ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3426 3426
3427 3427 mutex_enter(&fctl_nwwn_hash_mutex);
3428 3428 elem = fctl_nwwn_hash_table[index].fnl_headp;
3429 3429 while (elem != NULL) {
3430 3430 next = elem->fne_nodep;
3431 3431 if (next != NULL) {
3432 3432 mutex_enter(&next->fd_mutex);
3433 3433 if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3434 3434 rnodep = next;
3435 3435 rnodep->fd_numports++;
3436 3436 mutex_exit(&next->fd_mutex);
3437 3437 break;
3438 3438 }
3439 3439 mutex_exit(&next->fd_mutex);
3440 3440 }
3441 3441 elem = elem->fne_nextp;
3442 3442 }
3443 3443 mutex_exit(&fctl_nwwn_hash_mutex);
3444 3444
3445 3445 return (rnodep);
3446 3446 }
3447 3447
3448 3448
3449 3449 /*
3450 3450 * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
3451 3451 * the newly allocated struct. Only fails if the kmem_zalloc() fails.
3452 3452 */
3453 3453 fc_remote_port_t *
3454 3454 fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
3455 3455 uint32_t d_id, uchar_t recepient, int sleep)
3456 3456 {
3457 3457 fc_remote_port_t *pd;
3458 3458
3459 3459 ASSERT(MUTEX_HELD(&port->fp_mutex));
3460 3460 ASSERT(FC_IS_REAL_DEVICE(d_id));
3461 3461
3462 3462 if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
3463 3463 return (NULL);
3464 3464 }
3465 3465 fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
3466 3466 FC_LOGO_TOLERANCE_TIME_LIMIT);
3467 3467
3468 3468 mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
3469 3469
3470 3470 pd->pd_port_id.port_id = d_id;
3471 3471 pd->pd_port_name = *port_wwn;
3472 3472 pd->pd_port = port;
3473 3473 pd->pd_state = PORT_DEVICE_VALID;
3474 3474 pd->pd_type = PORT_DEVICE_NEW;
3475 3475 pd->pd_recepient = recepient;
3476 3476
3477 3477 return (pd);
3478 3478 }
3479 3479
3480 3480
3481 3481 /*
3482 3482 * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
3483 3483 */
3484 3484 void
3485 3485 fctl_dealloc_remote_port(fc_remote_port_t *pd)
3486 3486 {
3487 3487 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3488 3488
3489 3489 fctl_tc_destructor(&pd->pd_logo_tc);
3490 3490 mutex_destroy(&pd->pd_mutex);
3491 3491 kmem_free(pd, sizeof (*pd));
3492 3492 }
3493 3493
3494 3494 /*
3495 3495 * Add the given fc_remote_port_t onto the linked list of remote port
3496 3496 * devices associated with the given fc_remote_node_t. Does NOT add the
3497 3497 * fc_remote_port_t to the list if already exists on the list.
3498 3498 */
3499 3499 void
3500 3500 fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
3501 3501 fc_remote_port_t *pd)
3502 3502 {
3503 3503 fc_remote_port_t *last;
3504 3504 fc_remote_port_t *ports;
3505 3505
3506 3506 mutex_enter(&rnodep->fd_mutex);
3507 3507
3508 3508 last = NULL;
3509 3509 for (ports = rnodep->fd_portlistp; ports != NULL;
3510 3510 ports = ports->pd_port_next) {
3511 3511 if (ports == pd) {
3512 3512 /*
3513 3513 * The given fc_remote_port_t is already on the linked
3514 3514 * list chain for the given remote node, so bail now.
3515 3515 */
3516 3516 mutex_exit(&rnodep->fd_mutex);
3517 3517 return;
3518 3518 }
3519 3519 last = ports;
3520 3520 }
3521 3521
3522 3522 /* Add the fc_remote_port_t to the tail of the linked list */
3523 3523 if (last != NULL) {
3524 3524 last->pd_port_next = pd;
3525 3525 } else {
3526 3526 rnodep->fd_portlistp = pd;
3527 3527 }
3528 3528 pd->pd_port_next = NULL;
3529 3529
3530 3530 /*
3531 3531 * Link the fc_remote_port_t back to the associated fc_remote_node_t.
3532 3532 */
3533 3533 mutex_enter(&pd->pd_mutex);
3534 3534 pd->pd_remote_nodep = rnodep;
3535 3535 mutex_exit(&pd->pd_mutex);
3536 3536
3537 3537 mutex_exit(&rnodep->fd_mutex);
3538 3538 }
3539 3539
3540 3540
3541 3541 /*
3542 3542 * Remove the specified fc_remote_port_t from the linked list of remote ports
3543 3543 * for the given fc_remote_node_t.
3544 3544 *
3545 3545 * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
3546 3546 * list of the fc_remote_node_t.
3547 3547 *
3548 3548 * The fd_numports on the given fc_remote_node_t is decremented, and if
3549 3549 * it hits zero then this function also removes the fc_remote_node_t from the
3550 3550 * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
3551 3551 * are removed from the fctl_nwwn_hash_table[].
3552 3552 */
3553 3553 int
3554 3554 fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
3555 3555 fc_remote_port_t *pd)
3556 3556 {
3557 3557 int rcount = 0;
3558 3558 fc_remote_port_t *last;
3559 3559 fc_remote_port_t *ports;
3560 3560
3561 3561 ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3562 3562 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3563 3563
3564 3564 last = NULL;
3565 3565
3566 3566 mutex_enter(&fctl_nwwn_hash_mutex);
3567 3567
3568 3568 mutex_enter(&rnodep->fd_mutex);
3569 3569
3570 3570 /*
3571 3571 * Go thru the linked list of fc_remote_port_t structs for the given
3572 3572 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
3573 3573 */
3574 3574 ports = rnodep->fd_portlistp;
3575 3575 while (ports != NULL) {
3576 3576 if (ports == pd) {
3577 3577 break; /* Found the requested fc_remote_port_t */
3578 3578 }
3579 3579 last = ports;
3580 3580 ports = ports->pd_port_next;
3581 3581 }
3582 3582
3583 3583 if (ports) {
3584 3584 rcount = --rnodep->fd_numports;
3585 3585 if (rcount == 0) {
3586 3586 /* Note: this is only ever called from here */
3587 3587 fctl_delist_nwwn_table(rnodep);
3588 3588 }
3589 3589 if (last) {
3590 3590 last->pd_port_next = pd->pd_port_next;
3591 3591 } else {
3592 3592 rnodep->fd_portlistp = pd->pd_port_next;
3593 3593 }
3594 3594 mutex_enter(&pd->pd_mutex);
3595 3595 pd->pd_remote_nodep = NULL;
3596 3596 mutex_exit(&pd->pd_mutex);
3597 3597 }
3598 3598
3599 3599 pd->pd_port_next = NULL;
3600 3600
3601 3601 mutex_exit(&rnodep->fd_mutex);
3602 3602 mutex_exit(&fctl_nwwn_hash_mutex);
3603 3603
3604 3604 return (rcount);
3605 3605 }
3606 3606
3607 3607
3608 3608 /*
3609 3609 * Add the given fc_remote_port_t struct to the d_id table in the given
3610 3610 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
3611 3611 * fc_remote_port_t.
3612 3612 *
3613 3613 * No memory allocs are required, so this never fails, but it does use the
3614 3614 * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
3615 3615 * (There does not seem to be a way to tell the caller that a duplicate
3616 3616 * exists.)
3617 3617 */
3618 3618 void
3619 3619 fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3620 3620 {
3621 3621 struct d_id_hash *head;
3622 3622
3623 3623 ASSERT(MUTEX_HELD(&port->fp_mutex));
3624 3624 ASSERT(MUTEX_HELD(&pd->pd_mutex));
3625 3625
3626 3626 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
3627 3627 return;
3628 3628 }
3629 3629
3630 3630 head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id,
3631 3631 did_table_size)];
3632 3632
3633 3633 #ifdef DEBUG
3634 3634 {
3635 3635 int index;
3636 3636 fc_remote_port_t *tmp_pd;
3637 3637 struct d_id_hash *tmp_head;
3638 3638
3639 3639 /*
3640 3640 * Search down in each bucket for a duplicate pd
3641 3641 * Also search for duplicate D_IDs
3642 3642 * This DEBUG code will force an ASSERT if a duplicate
3643 3643 * is ever found.
3644 3644 */
3645 3645 for (index = 0; index < did_table_size; index++) {
3646 3646 tmp_head = &port->fp_did_table[index];
3647 3647
3648 3648 tmp_pd = tmp_head->d_id_head;
3649 3649 while (tmp_pd != NULL) {
3650 3650 ASSERT(tmp_pd != pd);
3651 3651
3652 3652 if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3653 3653 tmp_pd->pd_type != PORT_DEVICE_OLD) {
3654 3654 ASSERT(tmp_pd->pd_port_id.port_id !=
3655 3655 pd->pd_port_id.port_id);
3656 3656 }
3657 3657
3658 3658 tmp_pd = tmp_pd->pd_did_hnext;
3659 3659 }
3660 3660 }
3661 3661 }
3662 3662
3663 3663 bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack));
3664 3664 pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH);
3665 3665 #endif
3666 3666
3667 3667 pd->pd_did_hnext = head->d_id_head;
3668 3668 head->d_id_head = pd;
3669 3669
3670 3670 pd->pd_aux_flags |= PD_IN_DID_QUEUE;
3671 3671 head->d_id_count++;
3672 3672 }
3673 3673
3674 3674
3675 3675 /*
3676 3676 * Remove the given fc_remote_port_t struct from the d_id table in the given
3677 3677 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
3678 3678 * fc_remote_port_t.
3679 3679 *
3680 3680 * Does nothing if the requested fc_remote_port_t was not found.
3681 3681 */
3682 3682 void
3683 3683 fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3684 3684 {
3685 3685 uint32_t d_id;
3686 3686 struct d_id_hash *head;
3687 3687 fc_remote_port_t *pd_next;
3688 3688 fc_remote_port_t *last;
3689 3689
3690 3690 ASSERT(MUTEX_HELD(&port->fp_mutex));
3691 3691 ASSERT(MUTEX_HELD(&pd->pd_mutex));
3692 3692
3693 3693 d_id = pd->pd_port_id.port_id;
3694 3694 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3695 3695
3696 3696 pd_next = head->d_id_head;
3697 3697 last = NULL;
3698 3698 while (pd_next != NULL) {
3699 3699 if (pd == pd_next) {
3700 3700 break; /* Found the given fc_remote_port_t */
3701 3701 }
3702 3702 last = pd_next;
3703 3703 pd_next = pd_next->pd_did_hnext;
3704 3704 }
3705 3705
3706 3706 if (pd_next) {
3707 3707 /*
3708 3708 * Found the given fc_remote_port_t; now remove it from the
3709 3709 * d_id list.
3710 3710 */
3711 3711 head->d_id_count--;
3712 3712 if (last == NULL) {
3713 3713 head->d_id_head = pd->pd_did_hnext;
3714 3714 } else {
3715 3715 last->pd_did_hnext = pd->pd_did_hnext;
3716 3716 }
3717 3717 pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
3718 3718 pd->pd_did_hnext = NULL;
3719 3719 }
3720 3720 }
3721 3721
3722 3722
3723 3723 /*
3724 3724 * Add the given fc_remote_port_t struct to the pwwn table in the given
3725 3725 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
3726 3726 * in the fc_remote_port_t.
3727 3727 *
3728 3728 * No memory allocs are required, so this never fails.
3729 3729 */
3730 3730 void
3731 3731 fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3732 3732 {
3733 3733 int index;
3734 3734 struct pwwn_hash *head;
3735 3735
3736 3736 ASSERT(MUTEX_HELD(&port->fp_mutex));
3737 3737 ASSERT(MUTEX_HELD(&pd->pd_mutex));
3738 3738
3739 3739 ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE);
3740 3740
3741 3741 index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn),
3742 3742 pwwn_table_size);
3743 3743
3744 3744 head = &port->fp_pwwn_table[index];
3745 3745
3746 3746 #ifdef DEBUG
3747 3747 {
3748 3748 int index;
3749 3749 fc_remote_port_t *tmp_pd;
3750 3750 struct pwwn_hash *tmp_head;
3751 3751
3752 3752 /*
3753 3753 * Search down in each bucket for a duplicate pd
3754 3754 * Search also for a duplicate WWN
3755 3755 * Throw an ASSERT if any duplicate is found.
3756 3756 */
3757 3757 for (index = 0; index < pwwn_table_size; index++) {
3758 3758 tmp_head = &port->fp_pwwn_table[index];
3759 3759
3760 3760 tmp_pd = tmp_head->pwwn_head;
3761 3761 while (tmp_pd != NULL) {
3762 3762 ASSERT(tmp_pd != pd);
3763 3763
3764 3764 if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3765 3765 tmp_pd->pd_type != PORT_DEVICE_OLD) {
3766 3766 ASSERT(fctl_wwn_cmp(
3767 3767 &tmp_pd->pd_port_name,
3768 3768 &pd->pd_port_name) != 0);
3769 3769 }
3770 3770
3771 3771 tmp_pd = tmp_pd->pd_wwn_hnext;
3772 3772 }
3773 3773 }
3774 3774 }
3775 3775
3776 3776 bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack));
3777 3777 pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH);
3778 3778 #endif /* DEBUG */
3779 3779
3780 3780 pd->pd_wwn_hnext = head->pwwn_head;
3781 3781 head->pwwn_head = pd;
3782 3782
3783 3783 head->pwwn_count++;
3784 3784 /*
3785 3785 * Make sure we tie fp_dev_count to the size of the
3786 3786 * pwwn_table
3787 3787 */
3788 3788 port->fp_dev_count++;
3789 3789 }
3790 3790
3791 3791
3792 3792 /*
3793 3793 * Remove the given fc_remote_port_t struct from the pwwn table in the given
3794 3794 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
3795 3795 * in the fc_remote_port_t.
3796 3796 *
3797 3797 * Does nothing if the requested fc_remote_port_t was not found.
3798 3798 */
3799 3799 void
3800 3800 fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3801 3801 {
3802 3802 int index;
3803 3803 la_wwn_t pwwn;
3804 3804 struct pwwn_hash *head;
3805 3805 fc_remote_port_t *pd_next;
3806 3806 fc_remote_port_t *last;
3807 3807
3808 3808 ASSERT(MUTEX_HELD(&port->fp_mutex));
3809 3809 ASSERT(MUTEX_HELD(&pd->pd_mutex));
3810 3810
3811 3811 pwwn = pd->pd_port_name;
3812 3812 index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size);
3813 3813
3814 3814 head = &port->fp_pwwn_table[index];
3815 3815
3816 3816 last = NULL;
3817 3817 pd_next = head->pwwn_head;
3818 3818 while (pd_next != NULL) {
3819 3819 if (pd_next == pd) {
3820 3820 break; /* Found the given fc_remote_port_t */
3821 3821 }
3822 3822 last = pd_next;
3823 3823 pd_next = pd_next->pd_wwn_hnext;
3824 3824 }
3825 3825
3826 3826 if (pd_next) {
3827 3827 /*
3828 3828 * Found the given fc_remote_port_t; now remove it from the
3829 3829 * pwwn list.
3830 3830 */
3831 3831 head->pwwn_count--;
3832 3832 /*
3833 3833 * Make sure we tie fp_dev_count to the size of the
3834 3834 * pwwn_table
3835 3835 */
3836 3836 port->fp_dev_count--;
3837 3837 if (last == NULL) {
3838 3838 head->pwwn_head = pd->pd_wwn_hnext;
3839 3839 } else {
3840 3840 last->pd_wwn_hnext = pd->pd_wwn_hnext;
3841 3841 }
3842 3842 pd->pd_wwn_hnext = NULL;
3843 3843 }
3844 3844 }
3845 3845
3846 3846
3847 3847 /*
3848 3848 * Looks in the d_id table of the specified fc_local_port_t for the
3849 3849 * fc_remote_port_t that matches the given d_id. Hashes based upon
3850 3850 * the given d_id.
3851 3851 * Returns a pointer to the fc_remote_port_t struct, but does not update any
3852 3852 * reference counts or otherwise indicate that the fc_remote_port_t is in
3853 3853 * use.
3854 3854 */
3855 3855 fc_remote_port_t *
3856 3856 fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3857 3857 {
3858 3858 struct d_id_hash *head;
3859 3859 fc_remote_port_t *pd;
3860 3860
3861 3861 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3862 3862
3863 3863 mutex_enter(&port->fp_mutex);
3864 3864
3865 3865 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3866 3866
3867 3867 pd = head->d_id_head;
3868 3868 while (pd != NULL) {
3869 3869 mutex_enter(&pd->pd_mutex);
3870 3870 if (pd->pd_port_id.port_id == d_id) {
3871 3871 /* Match found -- break out of the loop */
3872 3872 mutex_exit(&pd->pd_mutex);
3873 3873 break;
3874 3874 }
3875 3875 mutex_exit(&pd->pd_mutex);
3876 3876 pd = pd->pd_did_hnext;
3877 3877 }
3878 3878
3879 3879 mutex_exit(&port->fp_mutex);
3880 3880
3881 3881 return (pd);
3882 3882 }
3883 3883
3884 3884
3885 3885 #ifndef __lock_lint /* uncomment when there is a consumer */
3886 3886
3887 3887 void
3888 3888 fc_ulp_hold_remote_port(opaque_t port_handle)
3889 3889 {
3890 3890 fc_remote_port_t *pd = port_handle;
3891 3891
3892 3892 mutex_enter(&pd->pd_mutex);
3893 3893 pd->pd_ref_count++;
3894 3894 mutex_exit(&pd->pd_mutex);
3895 3895 }
3896 3896
3897 3897 /*
3898 3898 * Looks in the d_id table of the specified fc_local_port_t for the
3899 3899 * fc_remote_port_t that matches the given d_id. Hashes based upon
3900 3900 * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3901 3901 *
3902 3902 * Increments pd_ref_count in the fc_remote_port_t if the
3903 3903 * fc_remote_port_t is found at the given d_id.
3904 3904 *
3905 3905 * The fc_remote_port_t is ignored (treated as non-existent) if either
3906 3906 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3907 3907 */
3908 3908 fc_remote_port_t *
3909 3909 fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3910 3910 {
3911 3911 struct d_id_hash *head;
3912 3912 fc_remote_port_t *pd;
3913 3913
3914 3914 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3915 3915
3916 3916 mutex_enter(&port->fp_mutex);
3917 3917
3918 3918 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3919 3919
3920 3920 pd = head->d_id_head;
3921 3921 while (pd != NULL) {
3922 3922 mutex_enter(&pd->pd_mutex);
3923 3923 if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
3924 3924 PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
3925 3925 ASSERT(pd->pd_ref_count >= 0);
3926 3926 pd->pd_ref_count++;
3927 3927 mutex_exit(&pd->pd_mutex);
3928 3928 break;
3929 3929 }
3930 3930 mutex_exit(&pd->pd_mutex);
3931 3931 pd = pd->pd_did_hnext;
3932 3932 }
3933 3933
3934 3934 mutex_exit(&port->fp_mutex);
3935 3935
3936 3936 return (pd);
3937 3937 }
3938 3938
3939 3939 #endif /* __lock_lint */
3940 3940
3941 3941 /*
3942 3942 * Looks in the pwwn table of the specified fc_local_port_t for the
3943 3943 * fc_remote_port_t that matches the given pwwn. Hashes based upon the
3944 3944 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3945 3945 * but does not update any reference counts or otherwise indicate that
3946 3946 * the fc_remote_port_t is in use.
3947 3947 */
3948 3948 fc_remote_port_t *
3949 3949 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
3950 3950 {
3951 3951 int index;
3952 3952 struct pwwn_hash *head;
3953 3953 fc_remote_port_t *pd;
3954 3954
3955 3955 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3956 3956
3957 3957 mutex_enter(&port->fp_mutex);
3958 3958
3959 3959 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3960 3960 head = &port->fp_pwwn_table[index];
3961 3961
3962 3962 pd = head->pwwn_head;
3963 3963 while (pd != NULL) {
3964 3964 mutex_enter(&pd->pd_mutex);
3965 3965 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3966 3966 mutex_exit(&pd->pd_mutex);
3967 3967 break;
3968 3968 }
3969 3969 mutex_exit(&pd->pd_mutex);
3970 3970 pd = pd->pd_wwn_hnext;
3971 3971 }
3972 3972
3973 3973 mutex_exit(&port->fp_mutex);
3974 3974
3975 3975 return (pd);
3976 3976 }
3977 3977
3978 3978
3979 3979 /*
3980 3980 * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
3981 3981 * the caller already hold the fp_mutex in the fc_local_port_t struct.
3982 3982 */
3983 3983 fc_remote_port_t *
3984 3984 fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
3985 3985 {
3986 3986 int index;
3987 3987 struct pwwn_hash *head;
3988 3988 fc_remote_port_t *pd;
3989 3989
3990 3990 ASSERT(MUTEX_HELD(&port->fp_mutex));
3991 3991
3992 3992 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3993 3993 head = &port->fp_pwwn_table[index];
3994 3994
3995 3995 pd = head->pwwn_head;
3996 3996 while (pd != NULL) {
3997 3997 mutex_enter(&pd->pd_mutex);
3998 3998 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3999 3999 mutex_exit(&pd->pd_mutex);
4000 4000 break;
4001 4001 }
4002 4002 mutex_exit(&pd->pd_mutex);
4003 4003 pd = pd->pd_wwn_hnext;
4004 4004 }
4005 4005
4006 4006 return (pd);
4007 4007 }
4008 4008
4009 4009
4010 4010 /*
4011 4011 * Looks in the pwwn table of the specified fc_local_port_t for the
4012 4012 * fc_remote_port_t that matches the given d_id. Hashes based upon the
4013 4013 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
4014 4014 *
4015 4015 * Increments pd_ref_count in the fc_remote_port_t if the
4016 4016 * fc_remote_port_t is found at the given pwwn.
4017 4017 *
4018 4018 * The fc_remote_port_t is ignored (treated as non-existent) if either
4019 4019 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
4020 4020 */
4021 4021 fc_remote_port_t *
4022 4022 fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
4023 4023 {
4024 4024 int index;
4025 4025 struct pwwn_hash *head;
4026 4026 fc_remote_port_t *pd;
4027 4027
4028 4028 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4029 4029
4030 4030 mutex_enter(&port->fp_mutex);
4031 4031
4032 4032 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
4033 4033 head = &port->fp_pwwn_table[index];
4034 4034
4035 4035 pd = head->pwwn_head;
4036 4036 while (pd != NULL) {
4037 4037 mutex_enter(&pd->pd_mutex);
4038 4038 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 &&
4039 4039 pd->pd_state != PORT_DEVICE_INVALID &&
4040 4040 pd->pd_type != PORT_DEVICE_OLD) {
4041 4041 ASSERT(pd->pd_ref_count >= 0);
4042 4042 pd->pd_ref_count++;
4043 4043 mutex_exit(&pd->pd_mutex);
4044 4044 break;
4045 4045 }
4046 4046 mutex_exit(&pd->pd_mutex);
4047 4047 pd = pd->pd_wwn_hnext;
4048 4048 }
4049 4049
4050 4050 mutex_exit(&port->fp_mutex);
4051 4051
4052 4052 return (pd);
4053 4053 }
4054 4054
4055 4055
4056 4056 /*
4057 4057 * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
4058 4058 * struct.
4059 4059 *
4060 4060 * If pd_ref_count reaches zero, then this function will see if the
4061 4061 * fc_remote_port_t has been marked for deallocation. If so (and also if there
4062 4062 * are no other potential operations in progress, as indicated by the
4063 4063 * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
4064 4064 * fctl_destroy_remote_port_t() is called to deconstruct/free the given
4065 4065 * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
4066 4066 * on the associated fc_local_port_t). If the associated fc_remote_node_t is no
4067 4067 * longer in use, then it too is deconstructed/freed.
4068 4068 */
4069 4069 void
4070 4070 fctl_release_remote_port(fc_remote_port_t *pd)
4071 4071 {
4072 4072 int remove = 0;
4073 4073 fc_remote_node_t *node;
4074 4074 fc_local_port_t *port;
4075 4075
4076 4076 mutex_enter(&pd->pd_mutex);
4077 4077 port = pd->pd_port;
4078 4078
4079 4079 ASSERT(pd->pd_ref_count > 0);
4080 4080 pd->pd_ref_count--;
4081 4081 if (pd->pd_ref_count == 0 &&
4082 4082 (pd->pd_aux_flags & PD_NEEDS_REMOVAL) &&
4083 4083 (pd->pd_flags != PD_ELS_IN_PROGRESS) &&
4084 4084 (pd->pd_flags != PD_ELS_MARK)) {
4085 4085 remove = 1;
4086 4086 pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL;
4087 4087 }
4088 4088 node = pd->pd_remote_nodep;
4089 4089 ASSERT(node != NULL);
4090 4090
4091 4091 mutex_exit(&pd->pd_mutex);
4092 4092
4093 4093 if (remove) {
4094 4094 /*
4095 4095 * The fc_remote_port_t struct has to go away now, so call the
4096 4096 * cleanup function to get it off the various lists and remove
4097 4097 * references to it in any other associated structs.
4098 4098 */
4099 4099 if (fctl_destroy_remote_port(port, pd) == 0) {
4100 4100 /*
4101 4101 * No more fc_remote_port_t references found in the
4102 4102 * associated fc_remote_node_t, so deallocate the
4103 4103 * fc_remote_node_t (if it even exists).
4104 4104 */
4105 4105 if (node) {
4106 4106 fctl_destroy_remote_node(node);
4107 4107 }
4108 4108 }
4109 4109 }
4110 4110 }
4111 4111
4112 4112
4113 4113 void
4114 4114 fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
4115 4115 int whole_map, int justcopy, int orphan)
4116 4116 {
4117 4117 int index;
4118 4118 int listlen;
4119 4119 int full_list;
4120 4120 int initiator;
4121 4121 uint32_t topology;
4122 4122 struct pwwn_hash *head;
4123 4123 fc_remote_port_t *pd;
4124 4124 fc_remote_port_t *old_pd;
4125 4125 fc_remote_port_t *last_pd;
4126 4126 fc_portmap_t *listptr;
4127 4127
4128 4128 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4129 4129
4130 4130 mutex_enter(&port->fp_mutex);
4131 4131
4132 4132 topology = port->fp_topology;
4133 4133
4134 4134 if (orphan) {
4135 4135 ASSERT(!FC_IS_TOP_SWITCH(topology));
4136 4136 }
4137 4137
4138 4138 for (full_list = listlen = index = 0;
4139 4139 index < pwwn_table_size; index++) {
4140 4140 head = &port->fp_pwwn_table[index];
4141 4141 pd = head->pwwn_head;
4142 4142 while (pd != NULL) {
4143 4143 full_list++;
4144 4144 mutex_enter(&pd->pd_mutex);
4145 4145 if (pd->pd_type != PORT_DEVICE_NOCHANGE) {
4146 4146 listlen++;
4147 4147 }
4148 4148 mutex_exit(&pd->pd_mutex);
4149 4149 pd = pd->pd_wwn_hnext;
4150 4150 }
4151 4151 }
4152 4152
4153 4153 if (whole_map == 0) {
4154 4154 if (listlen == 0 && *len == 0) {
4155 4155 *map = NULL;
4156 4156 *len = listlen;
4157 4157 mutex_exit(&port->fp_mutex);
4158 4158 return;
4159 4159 }
4160 4160 } else {
4161 4161 if (full_list == 0 && *len == 0) {
4162 4162 *map = NULL;
4163 4163 *len = full_list;
4164 4164 mutex_exit(&port->fp_mutex);
4165 4165 return;
4166 4166 }
4167 4167 }
4168 4168
4169 4169 if (*len == 0) {
4170 4170 ASSERT(*map == NULL);
4171 4171 if (whole_map == 0) {
4172 4172 listptr = *map = kmem_zalloc(
4173 4173 sizeof (*listptr) * listlen, KM_SLEEP);
4174 4174 *len = listlen;
4175 4175 } else {
4176 4176 listptr = *map = kmem_zalloc(
4177 4177 sizeof (*listptr) * full_list, KM_SLEEP);
4178 4178 *len = full_list;
4179 4179 }
4180 4180 } else {
4181 4181 /*
4182 4182 * By design this routine mandates the callers to
4183 4183 * ask for a whole map when they specify the length
4184 4184 * and the listptr.
4185 4185 */
4186 4186 ASSERT(whole_map == 1);
4187 4187 if (*len < full_list) {
4188 4188 *len = full_list;
4189 4189 mutex_exit(&port->fp_mutex);
4190 4190 return;
4191 4191 }
4192 4192 listptr = *map;
4193 4193 *len = full_list;
4194 4194 }
4195 4195
4196 4196 for (index = 0; index < pwwn_table_size; index++) {
4197 4197 head = &port->fp_pwwn_table[index];
4198 4198 last_pd = NULL;
4199 4199 pd = head->pwwn_head;
4200 4200 while (pd != NULL) {
4201 4201 mutex_enter(&pd->pd_mutex);
4202 4202 if ((whole_map == 0 &&
4203 4203 pd->pd_type == PORT_DEVICE_NOCHANGE) ||
4204 4204 pd->pd_state == PORT_DEVICE_INVALID) {
4205 4205 mutex_exit(&pd->pd_mutex);
4206 4206 last_pd = pd;
4207 4207 pd = pd->pd_wwn_hnext;
4208 4208 continue;
4209 4209 }
4210 4210 mutex_exit(&pd->pd_mutex);
4211 4211
4212 4212 fctl_copy_portmap(listptr, pd);
4213 4213
4214 4214 if (justcopy) {
4215 4215 last_pd = pd;
4216 4216 pd = pd->pd_wwn_hnext;
4217 4217 listptr++;
4218 4218 continue;
4219 4219 }
4220 4220
4221 4221 mutex_enter(&pd->pd_mutex);
4222 4222 ASSERT(pd->pd_state != PORT_DEVICE_INVALID);
4223 4223 if (pd->pd_type == PORT_DEVICE_OLD) {
4224 4224 listptr->map_pd = pd;
4225 4225 listptr->map_state = pd->pd_state =
4226 4226 PORT_DEVICE_INVALID;
4227 4227 /*
4228 4228 * Remove this from the PWWN hash table.
4229 4229 */
4230 4230 old_pd = pd;
4231 4231 pd = old_pd->pd_wwn_hnext;
4232 4232
4233 4233 if (last_pd == NULL) {
4234 4234 ASSERT(old_pd == head->pwwn_head);
4235 4235
4236 4236 head->pwwn_head = pd;
4237 4237 } else {
4238 4238 last_pd->pd_wwn_hnext = pd;
4239 4239 }
4240 4240 head->pwwn_count--;
4241 4241 /*
4242 4242 * Make sure we tie fp_dev_count to the size
4243 4243 * of the pwwn_table
4244 4244 */
4245 4245 port->fp_dev_count--;
4246 4246 old_pd->pd_wwn_hnext = NULL;
4247 4247
4248 4248 if (port->fp_topology == FC_TOP_PRIVATE_LOOP &&
4249 4249 port->fp_statec_busy && !orphan) {
4250 4250 fctl_check_alpa_list(port, old_pd);
4251 4251 }
4252 4252
4253 4253 /*
4254 4254 * Remove if the port device has stealthily
4255 4255 * present in the D_ID hash table
4256 4256 */
4257 4257 fctl_delist_did_table(port, old_pd);
4258 4258
4259 4259 ASSERT(old_pd->pd_remote_nodep != NULL);
4260 4260
4261 4261 initiator = (old_pd->pd_recepient ==
4262 4262 PD_PLOGI_INITIATOR) ? 1 : 0;
4263 4263
4264 4264 mutex_exit(&old_pd->pd_mutex);
4265 4265 mutex_exit(&port->fp_mutex);
4266 4266
4267 4267 if (orphan) {
4268 4268 fctl_print_if_not_orphan(port, old_pd);
4269 4269
4270 4270 (void) fctl_add_orphan(port, old_pd,
4271 4271 KM_NOSLEEP);
4272 4272 }
4273 4273
4274 4274 if (FC_IS_TOP_SWITCH(topology) && initiator) {
4275 4275 (void) fctl_add_orphan(port, old_pd,
4276 4276 KM_NOSLEEP);
4277 4277 }
4278 4278 mutex_enter(&port->fp_mutex);
4279 4279 } else {
4280 4280 listptr->map_pd = pd;
4281 4281 pd->pd_type = PORT_DEVICE_NOCHANGE;
4282 4282 mutex_exit(&pd->pd_mutex);
4283 4283 last_pd = pd;
4284 4284 pd = pd->pd_wwn_hnext;
4285 4285 }
4286 4286 listptr++;
4287 4287 }
4288 4288 }
4289 4289 mutex_exit(&port->fp_mutex);
4290 4290 }
4291 4291
4292 4292
4293 4293 job_request_t *
4294 4294 fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
4295 4295 opaque_t arg, int sleep)
4296 4296 {
4297 4297 job_request_t *job;
4298 4298
4299 4299 job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
4300 4300 if (job != NULL) {
4301 4301 job->job_result = FC_SUCCESS;
4302 4302 job->job_code = job_code;
4303 4303 job->job_flags = job_flags;
4304 4304 job->job_cb_arg = arg;
4305 4305 job->job_comp = comp;
4306 4306 job->job_private = NULL;
4307 4307 job->job_ulp_pkts = NULL;
4308 4308 job->job_ulp_listlen = 0;
4309 4309 #ifndef __lock_lint
4310 4310 job->job_counter = 0;
4311 4311 job->job_next = NULL;
4312 4312 #endif /* __lock_lint */
4313 4313 }
4314 4314
4315 4315 return (job);
4316 4316 }
4317 4317
4318 4318
4319 4319 void
4320 4320 fctl_dealloc_job(job_request_t *job)
4321 4321 {
4322 4322 kmem_cache_free(fctl_job_cache, (void *)job);
4323 4323 }
4324 4324
4325 4325
4326 4326 void
4327 4327 fctl_enque_job(fc_local_port_t *port, job_request_t *job)
4328 4328 {
4329 4329 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4330 4330
4331 4331 mutex_enter(&port->fp_mutex);
4332 4332
4333 4333 if (port->fp_job_tail == NULL) {
4334 4334 ASSERT(port->fp_job_head == NULL);
4335 4335 port->fp_job_head = port->fp_job_tail = job;
4336 4336 } else {
4337 4337 port->fp_job_tail->job_next = job;
4338 4338 port->fp_job_tail = job;
4339 4339 }
4340 4340 job->job_next = NULL;
4341 4341
4342 4342 cv_signal(&port->fp_cv);
4343 4343 mutex_exit(&port->fp_mutex);
4344 4344 }
4345 4345
4346 4346
4347 4347 job_request_t *
4348 4348 fctl_deque_job(fc_local_port_t *port)
4349 4349 {
4350 4350 job_request_t *job;
4351 4351
4352 4352 ASSERT(MUTEX_HELD(&port->fp_mutex));
4353 4353
4354 4354 if (port->fp_job_head == NULL) {
4355 4355 ASSERT(port->fp_job_tail == NULL);
4356 4356 job = NULL;
4357 4357 } else {
4358 4358 job = port->fp_job_head;
4359 4359 if (job->job_next == NULL) {
4360 4360 ASSERT(job == port->fp_job_tail);
4361 4361 port->fp_job_tail = NULL;
4362 4362 }
4363 4363 port->fp_job_head = job->job_next;
4364 4364 }
4365 4365
4366 4366 return (job);
4367 4367 }
4368 4368
4369 4369
4370 4370 void
4371 4371 fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job)
4372 4372 {
4373 4373 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4374 4374
4375 4375 mutex_enter(&port->fp_mutex);
4376 4376 if (port->fp_job_tail == NULL) {
4377 4377 ASSERT(port->fp_job_head == NULL);
4378 4378 port->fp_job_head = port->fp_job_tail = job;
4379 4379 job->job_next = NULL;
4380 4380 } else {
4381 4381 job->job_next = port->fp_job_head;
4382 4382 port->fp_job_head = job;
4383 4383 }
4384 4384 cv_signal(&port->fp_cv);
4385 4385 mutex_exit(&port->fp_mutex);
4386 4386 }
4387 4387
4388 4388
4389 4389 void
4390 4390 fctl_jobwait(job_request_t *job)
4391 4391 {
4392 4392 ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC));
4393 4393 sema_p(&job->job_fctl_sema);
4394 4394 ASSERT(!MUTEX_HELD(&job->job_mutex));
4395 4395 }
4396 4396
4397 4397
4398 4398 void
4399 4399 fctl_jobdone(job_request_t *job)
4400 4400 {
4401 4401 if (job->job_flags & JOB_TYPE_FCTL_ASYNC) {
4402 4402 if (job->job_comp) {
4403 4403 job->job_comp(job->job_cb_arg, job->job_result);
4404 4404 }
4405 4405 fctl_dealloc_job(job);
4406 4406 } else {
4407 4407 sema_v(&job->job_fctl_sema);
4408 4408 }
4409 4409 }
4410 4410
4411 4411
4412 4412 /*
4413 4413 * Compare two WWNs.
4414 4414 * The NAA can't be omitted for comparison.
4415 4415 *
4416 4416 * Return Values:
4417 4417 * if src == dst return 0
4418 4418 * if src > dst return 1
4419 4419 * if src < dst return -1
4420 4420 */
4421 4421 int
4422 4422 fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
4423 4423 {
4424 4424 uint8_t *l, *r;
4425 4425 int i;
4426 4426 uint64_t wl, wr;
4427 4427
4428 4428 l = (uint8_t *)src;
4429 4429 r = (uint8_t *)dst;
4430 4430
4431 4431 for (i = 0, wl = 0; i < 8; i++) {
4432 4432 wl <<= 8;
4433 4433 wl |= l[i];
4434 4434 }
4435 4435 for (i = 0, wr = 0; i < 8; i++) {
4436 4436 wr <<= 8;
4437 4437 wr |= r[i];
4438 4438 }
4439 4439
4440 4440 if (wl > wr) {
4441 4441 return (1);
4442 4442 } else if (wl == wr) {
4443 4443 return (0);
4444 4444 } else {
4445 4445 return (-1);
4446 4446 }
4447 4447 }
4448 4448
4449 4449
4450 4450 /*
4451 4451 * ASCII to Integer goodie with support for base 16, 10, 2 and 8
4452 4452 */
4453 4453 int
4454 4454 fctl_atoi(char *s, int base)
4455 4455 {
4456 4456 int val;
4457 4457 int ch;
4458 4458
4459 4459 for (val = 0; *s != '\0'; s++) {
4460 4460 switch (base) {
4461 4461 case 16:
4462 4462 if (*s >= '0' && *s <= '9') {
4463 4463 ch = *s - '0';
4464 4464 } else if (*s >= 'a' && *s <= 'f') {
4465 4465 ch = *s - 'a' + 10;
4466 4466 } else if (*s >= 'A' && *s <= 'F') {
4467 4467 ch = *s - 'A' + 10;
4468 4468 } else {
4469 4469 return (-1);
4470 4470 }
4471 4471 break;
4472 4472
4473 4473 case 10:
4474 4474 if (*s < '0' || *s > '9') {
4475 4475 return (-1);
4476 4476 }
4477 4477 ch = *s - '0';
4478 4478 break;
4479 4479
4480 4480 case 2:
4481 4481 if (*s < '0' || *s > '1') {
4482 4482 return (-1);
4483 4483 }
4484 4484 ch = *s - '0';
4485 4485 break;
4486 4486
4487 4487 case 8:
4488 4488 if (*s < '0' || *s > '7') {
4489 4489 return (-1);
4490 4490 }
4491 4491 ch = *s - '0';
4492 4492 break;
4493 4493
4494 4494 default:
4495 4495 return (-1);
4496 4496 }
4497 4497 val = (val * base) + ch;
4498 4498 }
4499 4499 return (val);
4500 4500 }
4501 4501
4502 4502
4503 4503 /*
4504 4504 * Create the fc_remote_port_t struct for the given port_wwn and d_id.
4505 4505 *
4506 4506 * If the struct already exists (and is "valid"), then use it. Before using
4507 4507 * it, the code below also checks: (a) if the d_id has changed, and (b) if
4508 4508 * the device is maked as PORT_DEVICE_OLD.
4509 4509 *
4510 4510 * If no fc_remote_node_t struct exists for the given node_wwn, then that
4511 4511 * struct is also created (and linked with the fc_remote_port_t).
4512 4512 *
4513 4513 * The given fc_local_port_t struct is updated with the info on the new
4514 4514 * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
4515 4515 * The global node_hash_table[] is updated (if necessary).
4516 4516 */
4517 4517 fc_remote_port_t *
4518 4518 fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
4519 4519 la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep)
4520 4520 {
4521 4521 int invalid = 0;
4522 4522 fc_remote_node_t *rnodep;
4523 4523 fc_remote_port_t *pd;
4524 4524
4525 4525 rnodep = fctl_get_remote_node_by_nwwn(node_wwn);
4526 4526 if (rnodep) {
4527 4527 /*
4528 4528 * We found an fc_remote_node_t for the remote node -- see if
4529 4529 * anyone has marked it as going away or gone.
4530 4530 */
4531 4531 mutex_enter(&rnodep->fd_mutex);
4532 4532 invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0;
4533 4533 mutex_exit(&rnodep->fd_mutex);
4534 4534 }
4535 4535 if (rnodep == NULL || invalid) {
4536 4536 /*
4537 4537 * No valid remote node struct found -- create it.
4538 4538 * Note: this is the only place that this func is called.
4539 4539 */
4540 4540 rnodep = fctl_create_remote_node(node_wwn, sleep);
4541 4541 if (rnodep == NULL) {
4542 4542 return (NULL);
4543 4543 }
4544 4544 }
4545 4545
4546 4546 mutex_enter(&port->fp_mutex);
4547 4547
4548 4548 /*
4549 4549 * See if there already is an fc_remote_port_t struct in existence
4550 4550 * on the specified fc_local_port_t for the given pwwn. If so, then
4551 4551 * grab a reference to it. The 'held' here just means that fp_mutex
4552 4552 * is held by the caller -- no reference counts are updated.
4553 4553 */
4554 4554 pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn);
4555 4555 if (pd) {
4556 4556 /*
4557 4557 * An fc_remote_port_t struct was found -- see if anyone has
4558 4558 * marked it as "invalid", which means that it is in the
4559 4559 * process of going away & we don't want to use it.
4560 4560 */
4561 4561 mutex_enter(&pd->pd_mutex);
4562 4562 invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0;
4563 4563 mutex_exit(&pd->pd_mutex);
4564 4564 }
4565 4565
4566 4566 if (pd == NULL || invalid) {
4567 4567 /*
4568 4568 * No fc_remote_port_t was found (or the existing one is
4569 4569 * marked as "invalid".) Allocate a new one and use that.
4570 4570 * This call will also update the d_id and pwwn hash tables
4571 4571 * in the given fc_local_port_t struct with the newly allocated
4572 4572 * fc_remote_port_t.
4573 4573 */
4574 4574 if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id,
4575 4575 recepient, sleep)) == NULL) {
4576 4576 /* Just give up if the allocation fails. */
4577 4577 mutex_exit(&port->fp_mutex);
4578 4578 fctl_destroy_remote_node(rnodep);
4579 4579 return (pd);
4580 4580 }
4581 4581
4582 4582 /*
4583 4583 * Add the new fc_remote_port_t struct to the d_id and pwwn
4584 4584 * hash tables on the associated fc_local_port_t struct.
4585 4585 */
4586 4586 mutex_enter(&pd->pd_mutex);
4587 4587 pd->pd_remote_nodep = rnodep;
4588 4588 fctl_enlist_did_table(port, pd);
4589 4589 fctl_enlist_pwwn_table(port, pd);
4590 4590 mutex_exit(&pd->pd_mutex);
4591 4591 mutex_exit(&port->fp_mutex);
4592 4592
4593 4593 /*
4594 4594 * Retrieve a pointer to the fc_remote_node_t (i.e., remote
4595 4595 * node) specified by the given node_wwn. This looks in the
4596 4596 * global fctl_nwwn_hash_table[]. The fd_numports reference
4597 4597 * count in the fc_remote_node_t struct is incremented.
4598 4598 */
4599 4599 rnodep = fctl_lock_remote_node_by_nwwn(node_wwn);
4600 4600
4601 4601 } else {
4602 4602 /*
4603 4603 * An existing and valid fc_remote_port_t struct already
4604 4604 * exists on the fc_local_port_t for the given pwwn.
4605 4605 */
4606 4606
4607 4607 mutex_enter(&pd->pd_mutex);
4608 4608 ASSERT(pd->pd_remote_nodep != NULL);
4609 4609
4610 4610 if (pd->pd_port_id.port_id != d_id) {
4611 4611 /*
4612 4612 * A very unlikely occurance in a well
4613 4613 * behaved environment.
4614 4614 */
4615 4615
4616 4616 /*
4617 4617 * The existing fc_remote_port_t has a different
4618 4618 * d_id than what we were given. This code will
4619 4619 * update the existing one with the one that was
4620 4620 * just given.
4621 4621 */
4622 4622 char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1];
4623 4623 uint32_t old_id;
4624 4624
4625 4625 fc_wwn_to_str(port_wwn, string);
4626 4626
4627 4627 old_id = pd->pd_port_id.port_id;
4628 4628
4629 4629 fctl_delist_did_table(port, pd);
4630 4630
4631 4631 cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device"
4632 4632 " with PWWN %s changed. New D_ID = %x,"
4633 4633 " OLD D_ID = %x", port->fp_instance, string,
4634 4634 d_id, old_id);
4635 4635
4636 4636 pd->pd_port_id.port_id = d_id;
4637 4637
4638 4638 /*
4639 4639 * Looks like we have to presume here that the
4640 4640 * remote port could be something entirely different
4641 4641 * from what was previously existing & valid at this
4642 4642 * pwwn.
4643 4643 */
4644 4644 pd->pd_type = PORT_DEVICE_CHANGED;
4645 4645
4646 4646 /* Record (update) the new d_id for the remote port */
4647 4647 fctl_enlist_did_table(port, pd);
4648 4648
4649 4649 } else if (pd->pd_type == PORT_DEVICE_OLD) {
4650 4650 /*
4651 4651 * OK at least the old & new d_id's match. So for
4652 4652 * PORT_DEVICE_OLD, this assumes that the remote
4653 4653 * port had disappeared but now has come back.
4654 4654 * Update the pd_type and pd_state to put the
4655 4655 * remote port back into service.
4656 4656 */
4657 4657 pd->pd_type = PORT_DEVICE_NOCHANGE;
4658 4658 pd->pd_state = PORT_DEVICE_VALID;
4659 4659
4660 4660 fctl_enlist_did_table(port, pd);
4661 4661
4662 4662 } else {
4663 4663 /*
4664 4664 * OK the old & new d_id's match, and the remote
4665 4665 * port struct is not marked as PORT_DEVICE_OLD, so
4666 4666 * presume that it's still the same device and is
4667 4667 * still in good shape. Also this presumes that we
4668 4668 * do not need to update d_id or pwwn hash tables.
4669 4669 */
4670 4670 /* sanitize device values */
4671 4671 pd->pd_type = PORT_DEVICE_NOCHANGE;
4672 4672 pd->pd_state = PORT_DEVICE_VALID;
4673 4673 }
4674 4674
4675 4675 mutex_exit(&pd->pd_mutex);
4676 4676 mutex_exit(&port->fp_mutex);
4677 4677
4678 4678 if (rnodep != pd->pd_remote_nodep) {
4679 4679 if ((rnodep != NULL) &&
4680 4680 (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name,
4681 4681 node_wwn) != 0)) {
4682 4682 /*
4683 4683 * Rut-roh, there is an fc_remote_node_t remote
4684 4684 * node struct for the given node_wwn, but the
4685 4685 * fc_remote_port_t remote port struct doesn't
4686 4686 * know about it. This just prints a warning
4687 4687 * message & fails the fc_remote_port_t
4688 4688 * allocation (possible leak here?).
4689 4689 */
4690 4690 char ww1_name[17];
4691 4691 char ww2_name[17];
4692 4692
4693 4693 fc_wwn_to_str(
4694 4694 &pd->pd_remote_nodep->fd_node_name,
4695 4695 ww1_name);
4696 4696 fc_wwn_to_str(node_wwn, ww2_name);
4697 4697
4698 4698 cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: "
4699 4699 "Expected %s Got %s", port->fp_instance,
4700 4700 ww1_name, ww2_name);
4701 4701 }
4702 4702
4703 4703 return (NULL);
4704 4704 }
4705 4705 }
4706 4706
4707 4707 /*
4708 4708 * Add the fc_remote_port_t onto the linked list of remote port
4709 4709 * devices associated with the given fc_remote_node_t (remote node).
4710 4710 */
4711 4711 fctl_link_remote_port_to_remote_node(rnodep, pd);
4712 4712
4713 4713 return (pd);
4714 4714 }
4715 4715
4716 4716
4717 4717 /*
4718 4718 * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
4719 4719 * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
4720 4720 * references to the fc_remote_port_t from the d_id and pwwn tables in the
4721 4721 * given fc_local_port_t. Deallocates the given fc_remote_port_t.
4722 4722 *
4723 4723 * Returns a count of the number of remaining fc_remote_port_t structs
4724 4724 * associated with the fc_remote_node_t struct.
4725 4725 *
4726 4726 * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
4727 4727 * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
4728 4728 * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
4729 4729 * the cleanup. The function then also returns '1'
4730 4730 * instead of the actual number of remaining fc_remote_port_t structs
4731 4731 *
4732 4732 * If there are no more remote ports on the remote node, return 0.
4733 4733 * Otherwise, return non-zero.
4734 4734 */
4735 4735 int
4736 4736 fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
4737 4737 {
4738 4738 fc_remote_node_t *rnodep;
4739 4739 int rcount = 0;
4740 4740
4741 4741 mutex_enter(&pd->pd_mutex);
4742 4742
4743 4743 /*
4744 4744 * If pd_ref_count > 0, we can't pull the rug out from any
4745 4745 * current users of this fc_remote_port_t. We'll mark it as old
4746 4746 * and in need of removal. The same goes for any fc_remote_port_t
4747 4747 * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
4748 4748 * have not yet been notified that the handle is no longer valid
4749 4749 * (i.e., PD_GIVEN_TO_ULPS is set).
4750 4750 */
4751 4751 if ((pd->pd_ref_count > 0) ||
4752 4752 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) {
4753 4753 pd->pd_aux_flags |= PD_NEEDS_REMOVAL;
4754 4754 pd->pd_type = PORT_DEVICE_OLD;
4755 4755 mutex_exit(&pd->pd_mutex);
4756 4756 return (1);
4757 4757 }
4758 4758
4759 4759 pd->pd_type = PORT_DEVICE_OLD;
4760 4760
4761 4761 rnodep = pd->pd_remote_nodep;
4762 4762
4763 4763 mutex_exit(&pd->pd_mutex);
4764 4764
4765 4765 if (rnodep != NULL) {
4766 4766 /*
4767 4767 * Remove the fc_remote_port_t from the linked list of remote
4768 4768 * ports for the given fc_remote_node_t. This is only called
4769 4769 * here and in fctl_destroy_all_remote_ports().
4770 4770 */
4771 4771 rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd);
4772 4772 }
4773 4773
4774 4774 mutex_enter(&port->fp_mutex);
4775 4775 mutex_enter(&pd->pd_mutex);
4776 4776
4777 4777 fctl_delist_did_table(port, pd);
4778 4778 fctl_delist_pwwn_table(port, pd);
4779 4779
4780 4780 mutex_exit(&pd->pd_mutex);
4781 4781
4782 4782 /*
4783 4783 * Deconstruct & free the fc_remote_port_t. This is only called
4784 4784 * here and in fctl_destroy_all_remote_ports().
4785 4785 */
4786 4786 fctl_dealloc_remote_port(pd);
4787 4787
4788 4788 mutex_exit(&port->fp_mutex);
4789 4789
4790 4790 return (rcount);
4791 4791 }
4792 4792
4793 4793
4794 4794 /*
4795 4795 * This goes thru the d_id table on the given fc_local_port_t.
4796 4796 * For each fc_remote_port_t found, this will:
4797 4797 *
4798 4798 * - Remove the fc_remote_port_t from the linked list of remote ports for
4799 4799 * the associated fc_remote_node_t. If the linked list goes empty, then this
4800 4800 * tries to deconstruct & free the fc_remote_node_t (that also removes the
4801 4801 * fc_remote_node_t from the global fctl_nwwn_hash_table[]).
4802 4802 *
4803 4803 * - Remove the fc_remote_port_t from the pwwn list on the given
4804 4804 * fc_local_port_t.
4805 4805 *
4806 4806 * - Deconstruct and free the fc_remote_port_t.
4807 4807 *
4808 4808 * - Removes the link to the fc_remote_port_t in the d_id table. Note, this
4809 4809 * does not appear to correctle decrement the d_id_count tho.
4810 4810 */
4811 4811 void
4812 4812 fctl_destroy_all_remote_ports(fc_local_port_t *port)
4813 4813 {
4814 4814 int index;
4815 4815 fc_remote_port_t *pd;
4816 4816 fc_remote_node_t *rnodep;
4817 4817 struct d_id_hash *head;
4818 4818
4819 4819 mutex_enter(&port->fp_mutex);
4820 4820
4821 4821 for (index = 0; index < did_table_size; index++) {
4822 4822
4823 4823 head = &port->fp_did_table[index];
4824 4824
4825 4825 while (head->d_id_head != NULL) {
4826 4826 pd = head->d_id_head;
4827 4827
4828 4828 /*
4829 4829 * See if this remote port (fc_remote_port_t) has a
4830 4830 * reference to a remote node (fc_remote_node_t) in its
4831 4831 * pd->pd_remote_nodep pointer.
4832 4832 */
4833 4833 mutex_enter(&pd->pd_mutex);
4834 4834 rnodep = pd->pd_remote_nodep;
4835 4835 mutex_exit(&pd->pd_mutex);
4836 4836
4837 4837 if (rnodep != NULL) {
4838 4838 /*
4839 4839 * An fc_remote_node_t reference exists. Remove
4840 4840 * the fc_remote_port_t from the linked list of
4841 4841 * remote ports for fc_remote_node_t.
4842 4842 */
4843 4843 if (fctl_unlink_remote_port_from_remote_node(
4844 4844 rnodep, pd) == 0) {
4845 4845 /*
4846 4846 * The fd_numports reference count
4847 4847 * in the fc_remote_node_t has come
4848 4848 * back as zero, so we can free the
4849 4849 * fc_remote_node_t. This also means
4850 4850 * that the fc_remote_node_t was
4851 4851 * removed from the
4852 4852 * fctl_nwwn_hash_table[].
4853 4853 *
4854 4854 * This will silently skip the
4855 4855 * kmem_free() if either the
4856 4856 * fd_numports is nonzero or
4857 4857 * the fd_port is not NULL in
4858 4858 * the fc_remote_node_t.
4859 4859 */
4860 4860 fctl_destroy_remote_node(rnodep);
4861 4861 }
4862 4862 }
4863 4863
4864 4864 /*
4865 4865 * Clean up the entry in the fc_local_port_t's pwwn
4866 4866 * table for the given fc_remote_port_t (i.e., the pd).
4867 4867 */
4868 4868 mutex_enter(&pd->pd_mutex);
4869 4869 fctl_delist_pwwn_table(port, pd);
4870 4870 pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
4871 4871 mutex_exit(&pd->pd_mutex);
4872 4872
4873 4873 /*
4874 4874 * Remove the current entry from the d_id list.
4875 4875 */
4876 4876 head->d_id_head = pd->pd_did_hnext;
4877 4877
4878 4878 /*
4879 4879 * Deconstruct & free the fc_remote_port_t (pd)
4880 4880 * Note: this is only called here and in
4881 4881 * fctl_destroy_remote_port_t().
4882 4882 */
4883 4883 fctl_dealloc_remote_port(pd);
4884 4884 }
4885 4885 }
4886 4886
4887 4887 mutex_exit(&port->fp_mutex);
4888 4888 }
4889 4889
4890 4890
4891 4891 int
4892 4892 fctl_is_wwn_zero(la_wwn_t *wwn)
4893 4893 {
4894 4894 int count;
4895 4895
4896 4896 for (count = 0; count < sizeof (la_wwn_t); count++) {
4897 4897 if (wwn->raw_wwn[count] != 0) {
4898 4898 return (FC_FAILURE);
4899 4899 }
4900 4900 }
4901 4901
4902 4902 return (FC_SUCCESS);
4903 4903 }
4904 4904
4905 4905
4906 4906 void
4907 4907 fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
4908 4908 {
4909 4909 int data_cb;
4910 4910 int check_type;
4911 4911 int rval;
4912 4912 uint32_t claimed;
4913 4913 fc_ulp_module_t *mod;
4914 4914 fc_ulp_ports_t *ulp_port;
4915 4915
4916 4916 claimed = 0;
4917 4917 check_type = 1;
4918 4918
4919 4919 switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) {
4920 4920 case R_CTL_DEVICE_DATA:
4921 4921 data_cb = 1;
4922 4922 break;
4923 4923
4924 4924 case R_CTL_EXTENDED_SVC:
4925 4925 check_type = 0;
4926 4926 /* FALLTHROUGH */
4927 4927
4928 4928 case R_CTL_FC4_SVC:
4929 4929 data_cb = 0;
4930 4930 break;
4931 4931
4932 4932 default:
4933 4933 mutex_enter(&port->fp_mutex);
4934 4934 ASSERT(port->fp_active_ubs > 0);
4935 4935 if (--(port->fp_active_ubs) == 0) {
4936 4936 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4937 4937 }
4938 4938 mutex_exit(&port->fp_mutex);
4939 4939 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4940 4940 1, &buf->ub_token);
4941 4941 return;
4942 4942 }
4943 4943
4944 4944 rw_enter(&fctl_ulp_lock, RW_READER);
4945 4945 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
4946 4946 if (check_type && mod->mod_info->ulp_type != type) {
4947 4947 continue;
4948 4948 }
4949 4949
4950 4950 rw_enter(&fctl_mod_ports_lock, RW_READER);
4951 4951 ulp_port = fctl_get_ulp_port(mod, port);
4952 4952 rw_exit(&fctl_mod_ports_lock);
4953 4953
4954 4954 if (ulp_port == NULL) {
4955 4955 continue;
4956 4956 }
4957 4957
4958 4958 mutex_enter(&ulp_port->port_mutex);
4959 4959 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
4960 4960 mutex_exit(&ulp_port->port_mutex);
4961 4961 continue;
4962 4962 }
4963 4963 mutex_exit(&ulp_port->port_mutex);
4964 4964
4965 4965 if (data_cb == 1) {
4966 4966 rval = mod->mod_info->ulp_data_callback(
4967 4967 mod->mod_info->ulp_handle,
4968 4968 (opaque_t)port, buf, claimed);
4969 4969 } else {
4970 4970 rval = mod->mod_info->ulp_els_callback(
4971 4971 mod->mod_info->ulp_handle,
4972 4972 (opaque_t)port, buf, claimed);
4973 4973 }
4974 4974
4975 4975 if (rval == FC_SUCCESS && claimed == 0) {
4976 4976 claimed = 1;
4977 4977 }
4978 4978 }
4979 4979 rw_exit(&fctl_ulp_lock);
4980 4980
4981 4981 if (claimed == 0) {
4982 4982 /*
4983 4983 * We should actually RJT since nobody claimed it.
4984 4984 */
4985 4985 mutex_enter(&port->fp_mutex);
4986 4986 ASSERT(port->fp_active_ubs > 0);
4987 4987 if (--(port->fp_active_ubs) == 0) {
4988 4988 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4989 4989 }
4990 4990 mutex_exit(&port->fp_mutex);
4991 4991 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4992 4992 1, &buf->ub_token);
4993 4993
4994 4994 } else {
4995 4995 mutex_enter(&port->fp_mutex);
4996 4996 if (--port->fp_active_ubs == 0) {
4997 4997 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4998 4998 }
4999 4999 mutex_exit(&port->fp_mutex);
5000 5000 }
5001 5001 }
5002 5002
5003 5003
5004 5004 /*
5005 5005 * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
5006 5006 *
5007 5007 * With all these mutexes held, we should make sure this function does not eat
5008 5008 * up much time.
5009 5009 */
5010 5010 void
5011 5011 fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd)
5012 5012 {
5013 5013 fc_remote_node_t *node;
5014 5014
5015 5015 ASSERT(MUTEX_HELD(&pd->pd_mutex));
5016 5016
5017 5017 map->map_pwwn = pd->pd_port_name;
5018 5018 map->map_did = pd->pd_port_id;
5019 5019 map->map_hard_addr = pd->pd_hard_addr;
5020 5020 map->map_state = pd->pd_state;
5021 5021 map->map_type = pd->pd_type;
5022 5022 map->map_flags = 0;
5023 5023
5024 5024 ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5025 5025
5026 5026 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5027 5027
5028 5028 node = pd->pd_remote_nodep;
5029 5029
5030 5030 ASSERT(MUTEX_HELD(&node->fd_mutex));
5031 5031
5032 5032 if (node) {
5033 5033 map->map_nwwn = node->fd_node_name;
5034 5034 }
5035 5035 map->map_pd = pd;
5036 5036 }
5037 5037
5038 5038 void
5039 5039 fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
5040 5040 {
5041 5041 fc_remote_node_t *node;
5042 5042
5043 5043 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
5044 5044
5045 5045 mutex_enter(&pd->pd_mutex);
5046 5046 map->map_pwwn = pd->pd_port_name;
5047 5047 map->map_did = pd->pd_port_id;
5048 5048 map->map_hard_addr = pd->pd_hard_addr;
5049 5049 map->map_state = pd->pd_state;
5050 5050 map->map_type = pd->pd_type;
5051 5051 map->map_flags = 0;
5052 5052
5053 5053 ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5054 5054
5055 5055 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5056 5056
5057 5057 node = pd->pd_remote_nodep;
5058 5058 mutex_exit(&pd->pd_mutex);
5059 5059
5060 5060 if (node) {
5061 5061 mutex_enter(&node->fd_mutex);
5062 5062 map->map_nwwn = node->fd_node_name;
5063 5063 mutex_exit(&node->fd_mutex);
5064 5064 }
5065 5065 map->map_pd = pd;
5066 5066 }
5067 5067
5068 5068
5069 5069 static int
5070 5070 fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5071 5071 {
5072 5072 int rval = FC_SUCCESS;
5073 5073
5074 5074 switch (ns_req->ns_cmd) {
5075 5075 case NS_RFT_ID: {
5076 5076 int count;
5077 5077 uint32_t *src;
5078 5078 uint32_t *dst;
5079 5079 ns_rfc_type_t *rfc;
5080 5080
5081 5081 rfc = (ns_rfc_type_t *)ns_req->ns_req_payload;
5082 5082
5083 5083 mutex_enter(&port->fp_mutex);
5084 5084 src = (uint32_t *)port->fp_fc4_types;
5085 5085 dst = (uint32_t *)rfc->rfc_types;
5086 5086
5087 5087 for (count = 0; count < 8; count++) {
5088 5088 *src++ |= *dst++;
5089 5089 }
5090 5090 mutex_exit(&port->fp_mutex);
5091 5091
5092 5092 break;
5093 5093 }
5094 5094
5095 5095 case NS_RSPN_ID: {
5096 5096 ns_spn_t *spn;
5097 5097
5098 5098 spn = (ns_spn_t *)ns_req->ns_req_payload;
5099 5099
5100 5100 mutex_enter(&port->fp_mutex);
5101 5101 port->fp_sym_port_namelen = spn->spn_len;
5102 5102 if (spn->spn_len) {
5103 5103 bcopy((caddr_t)spn + sizeof (ns_spn_t),
5104 5104 port->fp_sym_port_name, spn->spn_len);
5105 5105 }
5106 5106 mutex_exit(&port->fp_mutex);
5107 5107
5108 5108 break;
5109 5109 }
5110 5110
5111 5111 case NS_RSNN_NN: {
5112 5112 ns_snn_t *snn;
5113 5113
5114 5114 snn = (ns_snn_t *)ns_req->ns_req_payload;
5115 5115
5116 5116 mutex_enter(&port->fp_mutex);
5117 5117 port->fp_sym_node_namelen = snn->snn_len;
5118 5118 if (snn->snn_len) {
5119 5119 bcopy((caddr_t)snn + sizeof (ns_snn_t),
5120 5120 port->fp_sym_node_name, snn->snn_len);
5121 5121 }
5122 5122 mutex_exit(&port->fp_mutex);
5123 5123
5124 5124 break;
5125 5125 }
5126 5126
5127 5127 case NS_RIP_NN: {
5128 5128 ns_rip_t *rip;
5129 5129
5130 5130 rip = (ns_rip_t *)ns_req->ns_req_payload;
5131 5131
5132 5132 mutex_enter(&port->fp_mutex);
5133 5133 bcopy(rip->rip_ip_addr, port->fp_ip_addr,
5134 5134 sizeof (rip->rip_ip_addr));
5135 5135 mutex_exit(&port->fp_mutex);
5136 5136
5137 5137 break;
5138 5138 }
5139 5139
5140 5140 case NS_RIPA_NN: {
5141 5141 ns_ipa_t *ipa;
5142 5142
5143 5143 ipa = (ns_ipa_t *)ns_req->ns_req_payload;
5144 5144
5145 5145 mutex_enter(&port->fp_mutex);
5146 5146 bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value));
5147 5147 mutex_exit(&port->fp_mutex);
5148 5148
5149 5149 break;
5150 5150 }
5151 5151
5152 5152 default:
5153 5153 rval = FC_BADOBJECT;
5154 5154 break;
5155 5155 }
5156 5156
5157 5157 return (rval);
5158 5158 }
5159 5159
5160 5160
5161 5161 static int
5162 5162 fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5163 5163 {
5164 5164 int rval = FC_SUCCESS;
5165 5165
5166 5166 switch (ns_req->ns_cmd) {
5167 5167 case NS_GFT_ID: {
5168 5168 ns_rfc_type_t *rfc;
5169 5169
5170 5170 rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload;
5171 5171
5172 5172 mutex_enter(&port->fp_mutex);
5173 5173 bcopy(port->fp_fc4_types, rfc->rfc_types,
5174 5174 sizeof (rfc->rfc_types));
5175 5175 mutex_exit(&port->fp_mutex);
5176 5176 break;
5177 5177 }
5178 5178
5179 5179 case NS_GSPN_ID: {
5180 5180 ns_spn_t *spn;
5181 5181
5182 5182 spn = (ns_spn_t *)ns_req->ns_resp_payload;
5183 5183
5184 5184 mutex_enter(&port->fp_mutex);
5185 5185 spn->spn_len = port->fp_sym_port_namelen;
5186 5186 if (spn->spn_len) {
5187 5187 bcopy(port->fp_sym_port_name, (caddr_t)spn +
5188 5188 sizeof (ns_spn_t), spn->spn_len);
5189 5189 }
5190 5190 mutex_exit(&port->fp_mutex);
5191 5191
5192 5192 break;
5193 5193 }
5194 5194
5195 5195 case NS_GSNN_NN: {
5196 5196 ns_snn_t *snn;
5197 5197
5198 5198 snn = (ns_snn_t *)ns_req->ns_resp_payload;
5199 5199
5200 5200 mutex_enter(&port->fp_mutex);
5201 5201 snn->snn_len = port->fp_sym_node_namelen;
5202 5202 if (snn->snn_len) {
5203 5203 bcopy(port->fp_sym_node_name, (caddr_t)snn +
5204 5204 sizeof (ns_snn_t), snn->snn_len);
5205 5205 }
5206 5206 mutex_exit(&port->fp_mutex);
5207 5207
5208 5208 break;
5209 5209 }
5210 5210
5211 5211 case NS_GIP_NN: {
5212 5212 ns_rip_t *rip;
5213 5213
5214 5214 rip = (ns_rip_t *)ns_req->ns_resp_payload;
5215 5215
5216 5216 mutex_enter(&port->fp_mutex);
5217 5217 bcopy(port->fp_ip_addr, rip->rip_ip_addr,
5218 5218 sizeof (rip->rip_ip_addr));
5219 5219 mutex_exit(&port->fp_mutex);
5220 5220
5221 5221 break;
5222 5222 }
5223 5223
5224 5224 case NS_GIPA_NN: {
5225 5225 ns_ipa_t *ipa;
5226 5226
5227 5227 ipa = (ns_ipa_t *)ns_req->ns_resp_payload;
5228 5228
5229 5229 mutex_enter(&port->fp_mutex);
5230 5230 bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value));
5231 5231 mutex_exit(&port->fp_mutex);
5232 5232
5233 5233 break;
5234 5234 }
5235 5235
5236 5236 default:
5237 5237 rval = FC_BADOBJECT;
5238 5238 break;
5239 5239 }
5240 5240
5241 5241 return (rval);
5242 5242 }
5243 5243
5244 5244
5245 5245 fctl_ns_req_t *
5246 5246 fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len,
5247 5247 uint32_t ns_flags, int sleep)
5248 5248 {
5249 5249 fctl_ns_req_t *ns_cmd;
5250 5250
5251 5251 ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep);
5252 5252 if (ns_cmd == NULL) {
5253 5253 return (NULL);
5254 5254 }
5255 5255
5256 5256 if (cmd_len) {
5257 5257 ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep);
5258 5258 if (ns_cmd->ns_cmd_buf == NULL) {
5259 5259 kmem_free(ns_cmd, sizeof (*ns_cmd));
5260 5260 return (NULL);
5261 5261 }
5262 5262 ns_cmd->ns_cmd_size = cmd_len;
5263 5263 }
5264 5264
5265 5265 ns_cmd->ns_resp_size = resp_len;
5266 5266
5267 5267 if (data_len) {
5268 5268 ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep);
5269 5269 if (ns_cmd->ns_data_buf == NULL) {
5270 5270 if (ns_cmd->ns_cmd_buf && cmd_len) {
5271 5271 kmem_free(ns_cmd->ns_cmd_buf, cmd_len);
5272 5272 }
5273 5273 kmem_free(ns_cmd, sizeof (*ns_cmd));
5274 5274 return (NULL);
5275 5275 }
5276 5276 ns_cmd->ns_data_len = data_len;
5277 5277 }
5278 5278 ns_cmd->ns_flags = ns_flags;
5279 5279
5280 5280 return (ns_cmd);
5281 5281 }
5282 5282
5283 5283
5284 5284 void
5285 5285 fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd)
5286 5286 {
5287 5287 if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) {
5288 5288 kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size);
5289 5289 }
5290 5290 if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) {
5291 5291 kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len);
5292 5292 }
5293 5293 kmem_free(ns_cmd, sizeof (*ns_cmd));
5294 5294 }
5295 5295
5296 5296
5297 5297 int
5298 5298 fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
5299 5299 intptr_t data, int mode, cred_t *credp, int *rval)
5300 5300 {
5301 5301 int ret;
5302 5302 int save;
5303 5303 uint32_t claimed;
5304 5304 fc_ulp_module_t *mod;
5305 5305 fc_ulp_ports_t *ulp_port;
5306 5306
5307 5307 save = *rval;
5308 5308 *rval = ENOTTY;
5309 5309
5310 5310 rw_enter(&fctl_ulp_lock, RW_READER);
5311 5311 for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
5312 5312 rw_enter(&fctl_mod_ports_lock, RW_READER);
5313 5313 ulp_port = fctl_get_ulp_port(mod, port);
5314 5314 rw_exit(&fctl_mod_ports_lock);
5315 5315
5316 5316 if (ulp_port == NULL) {
5317 5317 continue;
5318 5318 }
5319 5319
5320 5320 mutex_enter(&ulp_port->port_mutex);
5321 5321 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) ||
5322 5322 mod->mod_info->ulp_port_ioctl == NULL) {
5323 5323 mutex_exit(&ulp_port->port_mutex);
5324 5324 continue;
5325 5325 }
5326 5326 mutex_exit(&ulp_port->port_mutex);
5327 5327
5328 5328 ret = mod->mod_info->ulp_port_ioctl(
5329 5329 mod->mod_info->ulp_handle, (opaque_t)port,
5330 5330 dev, cmd, data, mode, credp, rval, claimed);
5331 5331
5332 5332 if (ret == FC_SUCCESS && claimed == 0) {
5333 5333 claimed = 1;
5334 5334 }
5335 5335 }
5336 5336 rw_exit(&fctl_ulp_lock);
5337 5337
5338 5338 ret = *rval;
5339 5339 *rval = save;
5340 5340
5341 5341 return (ret);
5342 5342 }
5343 5343
5344 5344 /*
5345 5345 * raise power if necessary, and set the port busy
5346 5346 *
5347 5347 * this may cause power to be raised, so no power related locks should
5348 5348 * be held
5349 5349 */
5350 5350 int
5351 5351 fc_ulp_busy_port(opaque_t port_handle)
5352 5352 {
5353 5353 fc_local_port_t *port = port_handle;
5354 5354
5355 5355 return (fctl_busy_port(port));
5356 5356 }
5357 5357
5358 5358 void
5359 5359 fc_ulp_idle_port(opaque_t port_handle)
5360 5360 {
5361 5361 fc_local_port_t *port = port_handle;
5362 5362 fctl_idle_port(port);
5363 5363 }
5364 5364
5365 5365 void
5366 5366 fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd)
5367 5367 {
5368 5368 fctl_copy_portmap(map, (fc_remote_port_t *)pd);
5369 5369 }
5370 5370
5371 5371
5372 5372 int
5373 5373 fc_ulp_get_npiv_port_num(opaque_t port_handle)
5374 5374 {
5375 5375 int portsnum = 0;
5376 5376 fc_local_port_t *port = port_handle;
5377 5377 fc_local_port_t *tmpport;
5378 5378
5379 5379 mutex_enter(&port->fp_mutex);
5380 5380 tmpport = port->fp_port_next;
5381 5381 if (!tmpport) {
5382 5382 mutex_exit(&port->fp_mutex);
5383 5383 return (portsnum);
5384 5384 }
5385 5385 while (tmpport != port) {
5386 5386 portsnum ++;
5387 5387 tmpport = tmpport->fp_port_next;
5388 5388 }
5389 5389 mutex_exit(&port->fp_mutex);
5390 5390 return (portsnum);
5391 5391 }
5392 5392
5393 5393 fc_local_port_t *
5394 5394 fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn)
5395 5395 {
5396 5396 fc_fca_port_t *fca_port;
5397 5397 fc_local_port_t *tmpPort = phyport;
5398 5398
5399 5399 mutex_enter(&fctl_port_lock);
5400 5400
5401 5401 for (fca_port = fctl_fca_portlist; fca_port != NULL;
5402 5402 fca_port = fca_port->port_next) {
5403 5403 tmpPort = fca_port->port_handle;
5404 5404 if (tmpPort == NULL) {
5405 5405 continue;
5406 5406 }
5407 5407 mutex_enter(&tmpPort->fp_mutex);
5408 5408 if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn,
5409 5409 pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) {
5410 5410 mutex_exit(&tmpPort->fp_mutex);
5411 5411 mutex_exit(&fctl_port_lock);
5412 5412 return (tmpPort);
5413 5413 }
5414 5414 mutex_exit(&tmpPort->fp_mutex);
5415 5415 }
5416 5416
5417 5417 mutex_exit(&fctl_port_lock);
5418 5418
5419 5419 return (NULL);
5420 5420 }
5421 5421
5422 5422 int
5423 5423 fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList)
5424 5424 {
5425 5425 int portsnum = 0;
5426 5426 fc_local_port_t *port = port_handle;
5427 5427 fc_local_port_t *tmpport;
5428 5428
5429 5429 mutex_enter(&port->fp_mutex);
5430 5430 tmpport = port->fp_port_next;
5431 5431 if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5432 5432 mutex_exit(&port->fp_mutex);
5433 5433 return (portsnum);
5434 5434 }
5435 5435
5436 5436 while (tmpport != port) {
5437 5437 (void) ddi_pathname(tmpport->fp_port_dip,
5438 5438 &pathList[MAXPATHLEN * portsnum]);
5439 5439 portsnum ++;
5440 5440 tmpport = tmpport->fp_port_next;
5441 5441 }
5442 5442 mutex_exit(&port->fp_mutex);
5443 5443
5444 5444 return (portsnum);
5445 5445 }
5446 5446
5447 5447
5448 5448 fc_local_port_t *
5449 5449 fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
5450 5450 {
5451 5451 fc_local_port_t *tmpport;
5452 5452
5453 5453 mutex_enter(&port->fp_mutex);
5454 5454 tmpport = port->fp_port_next;
5455 5455 if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5456 5456 mutex_exit(&port->fp_mutex);
5457 5457 return (NULL);
5458 5458 }
5459 5459
5460 5460 while (tmpport != port) {
5461 5461 if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn,
5462 5462 pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) &&
5463 5463 (tmpport->fp_npiv_state == 0)) {
5464 5464 tmpport->fp_npiv_state = FC_NPIV_DELETING;
5465 5465 mutex_exit(&port->fp_mutex);
5466 5466 return (tmpport);
5467 5467 }
5468 5468 tmpport = tmpport->fp_port_next;
5469 5469 }
5470 5470
5471 5471 mutex_exit(&port->fp_mutex);
5472 5472 return (NULL);
5473 5473 }
5474 5474
5475 5475 /*
5476 5476 * Get the list of Adapters. On multi-ported adapters,
5477 5477 * only ONE port on the adapter will be returned.
5478 5478 * pathList should be (count * MAXPATHLEN) long.
5479 5479 * The return value will be set to the number of
5480 5480 * HBAs that were found on the system. If the value
5481 5481 * is greater than count, the routine should be retried
5482 5482 * with a larger buffer.
5483 5483 */
5484 5484 int
5485 5485 fc_ulp_get_adapter_paths(char *pathList, int count)
5486 5486 {
5487 5487 fc_fca_port_t *fca_port;
5488 5488 int in = 0, out = 0, check, skip, maxPorts = 0;
5489 5489 fc_local_port_t **portList;
5490 5490 fc_local_port_t *new_port, *stored_port;
5491 5491 fca_hba_fru_details_t *new_fru, *stored_fru;
5492 5492
5493 5493 ASSERT(pathList != NULL);
5494 5494
5495 5495 /* First figure out how many ports we have */
5496 5496 mutex_enter(&fctl_port_lock);
5497 5497
5498 5498 for (fca_port = fctl_fca_portlist; fca_port != NULL;
5499 5499 fca_port = fca_port->port_next) {
5500 5500 maxPorts ++;
5501 5501 }
5502 5502
5503 5503 /* Now allocate a buffer to store all the pointers for comparisons */
5504 5504 portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP);
5505 5505
5506 5506 for (fca_port = fctl_fca_portlist; fca_port != NULL;
5507 5507 fca_port = fca_port->port_next) {
5508 5508 skip = 0;
5509 5509
5510 5510 /* Lock the new port for subsequent comparisons */
5511 5511 new_port = fca_port->port_handle;
5512 5512 mutex_enter(&new_port->fp_mutex);
5513 5513 new_fru = &new_port->fp_hba_port_attrs.hba_fru_details;
5514 5514
5515 5515 /* Filter out secondary ports from the list */
5516 5516 for (check = 0; check < out; check++) {
5517 5517 if (portList[check] == NULL) {
5518 5518 continue;
5519 5519 }
5520 5520 /* Guard against duplicates (should never happen) */
5521 5521 if (portList[check] == fca_port->port_handle) {
5522 5522 /* Same port */
5523 5523 skip = 1;
5524 5524 break;
5525 5525 }
5526 5526
5527 5527 /* Lock the already stored port for comparison */
5528 5528 stored_port = portList[check];
5529 5529 mutex_enter(&stored_port->fp_mutex);
5530 5530 stored_fru =
5531 5531 &stored_port->fp_hba_port_attrs.hba_fru_details;
5532 5532
5533 5533 /* Are these ports on the same HBA? */
5534 5534 if (new_fru->high == stored_fru->high &&
5535 5535 new_fru->low == stored_fru->low) {
5536 5536 /* Now double check driver */
5537 5537 if (strncmp(
5538 5538 new_port->fp_hba_port_attrs.driver_name,
5539 5539 stored_port->fp_hba_port_attrs.driver_name,
5540 5540 FCHBA_DRIVER_NAME_LEN) == 0) {
5541 5541 /* we don't need to grow the list */
5542 5542 skip = 1;
5543 5543 /* looking at a lower port index? */
5544 5544 if (new_fru->port_index <
5545 5545 stored_fru->port_index) {
5546 5546 /* Replace the port in list */
5547 5547 mutex_exit(
5548 5548 &stored_port->fp_mutex);
5549 5549 if (new_port->fp_npiv_type ==
5550 5550 FC_NPIV_PORT) {
5551 5551 break;
5552 5552 }
5553 5553 portList[check] = new_port;
5554 5554 break;
5555 5555 } /* Else, just skip this port */
5556 5556 }
5557 5557 }
5558 5558
5559 5559 mutex_exit(&stored_port->fp_mutex);
5560 5560 }
5561 5561 mutex_exit(&new_port->fp_mutex);
5562 5562
5563 5563 if (!skip) {
5564 5564 /*
5565 5565 * Either this is the first port for this HBA, or
5566 5566 * it's a secondary port and we haven't stored the
5567 5567 * primary/first port for that HBA. In the latter case,
5568 5568 * will just filter it out as we proceed to loop.
5569 5569 */
5570 5570 if (fca_port->port_handle->fp_npiv_type ==
5571 5571 FC_NPIV_PORT) {
5572 5572 continue;
5573 5573 } else {
5574 5574 portList[out++] = fca_port->port_handle;
5575 5575 }
5576 5576 }
5577 5577 }
5578 5578
5579 5579 if (out <= count) {
5580 5580 for (in = 0; in < out; in++) {
5581 5581 (void) ddi_pathname(portList[in]->fp_port_dip,
5582 5582 &pathList[MAXPATHLEN * in]);
5583 5583 }
5584 5584 }
5585 5585 mutex_exit(&fctl_port_lock);
5586 5586 kmem_free(portList, sizeof (*portList) * maxPorts);
5587 5587 return (out);
5588 5588 }
5589 5589
5590 5590 uint32_t
5591 5591 fc_ulp_get_rscn_count(opaque_t port_handle)
5592 5592 {
5593 5593 uint32_t count;
5594 5594 fc_local_port_t *port;
5595 5595
5596 5596 port = (fc_local_port_t *)port_handle;
5597 5597 mutex_enter(&port->fp_mutex);
5598 5598 count = port->fp_rscn_count;
5599 5599 mutex_exit(&port->fp_mutex);
5600 5600
5601 5601 return (count);
5602 5602 }
5603 5603
5604 5604
5605 5605 /*
5606 5606 * This function is a very similar to fctl_add_orphan except that it expects
5607 5607 * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
5608 5608 *
5609 5609 * Note that there is a lock hierarchy here (fp_mutex should be held first) but
5610 5610 * since this function could be called with a different pd's pd_mutex held, we
5611 5611 * should take care not to release fp_mutex in this function.
5612 5612 */
5613 5613 int
5614 5614 fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
5615 5615 {
5616 5616 int rval = FC_FAILURE;
5617 5617 la_wwn_t pwwn;
5618 5618 fc_orphan_t *orp;
5619 5619 fc_orphan_t *orphan;
5620 5620
5621 5621 ASSERT(MUTEX_HELD(&port->fp_mutex));
5622 5622 ASSERT(MUTEX_HELD(&pd->pd_mutex));
5623 5623
5624 5624 pwwn = pd->pd_port_name;
5625 5625
5626 5626 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5627 5627 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5628 5628 return (FC_SUCCESS);
5629 5629 }
5630 5630 }
5631 5631
5632 5632 orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP);
5633 5633 if (orphan) {
5634 5634 orphan->orp_pwwn = pwwn;
5635 5635 orphan->orp_tstamp = ddi_get_lbolt();
5636 5636
5637 5637 if (port->fp_orphan_list) {
5638 5638 ASSERT(port->fp_orphan_count > 0);
5639 5639 orphan->orp_next = port->fp_orphan_list;
5640 5640 }
5641 5641 port->fp_orphan_list = orphan;
5642 5642 port->fp_orphan_count++;
5643 5643
5644 5644 rval = FC_SUCCESS;
5645 5645 }
5646 5646
5647 5647 return (rval);
5648 5648 }
5649 5649
5650 5650 int
5651 5651 fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
5652 5652 {
5653 5653 int rval = FC_FAILURE;
5654 5654 la_wwn_t pwwn;
5655 5655 fc_orphan_t *orp;
5656 5656 fc_orphan_t *orphan;
5657 5657
5658 5658 mutex_enter(&port->fp_mutex);
5659 5659
5660 5660 mutex_enter(&pd->pd_mutex);
5661 5661 pwwn = pd->pd_port_name;
5662 5662 mutex_exit(&pd->pd_mutex);
5663 5663
5664 5664 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5665 5665 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5666 5666 mutex_exit(&port->fp_mutex);
5667 5667 return (FC_SUCCESS);
5668 5668 }
5669 5669 }
5670 5670 mutex_exit(&port->fp_mutex);
5671 5671
5672 5672 orphan = kmem_zalloc(sizeof (*orphan), sleep);
5673 5673 if (orphan != NULL) {
5674 5674 mutex_enter(&port->fp_mutex);
5675 5675
5676 5676 orphan->orp_pwwn = pwwn;
5677 5677 orphan->orp_tstamp = ddi_get_lbolt();
5678 5678
5679 5679 if (port->fp_orphan_list) {
5680 5680 ASSERT(port->fp_orphan_count > 0);
5681 5681 orphan->orp_next = port->fp_orphan_list;
5682 5682 }
5683 5683 port->fp_orphan_list = orphan;
5684 5684 port->fp_orphan_count++;
5685 5685 mutex_exit(&port->fp_mutex);
5686 5686
5687 5687 rval = FC_SUCCESS;
5688 5688 }
5689 5689
5690 5690 return (rval);
5691 5691 }
5692 5692
5693 5693
5694 5694 int
5695 5695 fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
5696 5696 {
5697 5697 int rval = FC_FAILURE;
5698 5698 fc_orphan_t *prev = NULL;
5699 5699 fc_orphan_t *orp;
5700 5700
5701 5701 mutex_enter(&port->fp_mutex);
5702 5702 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5703 5703 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) {
5704 5704 if (prev) {
5705 5705 prev->orp_next = orp->orp_next;
5706 5706 } else {
5707 5707 ASSERT(port->fp_orphan_list == orp);
5708 5708 port->fp_orphan_list = orp->orp_next;
5709 5709 }
5710 5710 port->fp_orphan_count--;
5711 5711 rval = FC_SUCCESS;
5712 5712 break;
5713 5713 }
5714 5714 prev = orp;
5715 5715 }
5716 5716 mutex_exit(&port->fp_mutex);
5717 5717
5718 5718 if (rval == FC_SUCCESS) {
5719 5719 kmem_free(orp, sizeof (*orp));
5720 5720 }
5721 5721
5722 5722 return (rval);
5723 5723 }
5724 5724
5725 5725
5726 5726 static void
5727 5727 fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
5728 5728 {
5729 5729 char ww_name[17];
5730 5730 la_wwn_t pwwn;
5731 5731 fc_orphan_t *orp;
5732 5732
5733 5733 mutex_enter(&port->fp_mutex);
5734 5734
5735 5735 mutex_enter(&pd->pd_mutex);
5736 5736 pwwn = pd->pd_port_name;
5737 5737 mutex_exit(&pd->pd_mutex);
5738 5738
5739 5739 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5740 5740 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5741 5741 mutex_exit(&port->fp_mutex);
5742 5742 return;
5743 5743 }
5744 5744 }
5745 5745 mutex_exit(&port->fp_mutex);
5746 5746
5747 5747 fc_wwn_to_str(&pwwn, ww_name);
5748 5748
5749 5749 cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
5750 5750 " disappeared from fabric", port->fp_instance,
5751 5751 pd->pd_port_id.port_id, ww_name);
5752 5752 }
5753 5753
5754 5754
5755 5755 /* ARGSUSED */
5756 5756 static void
5757 5757 fctl_link_reset_done(opaque_t port_handle, uchar_t result)
5758 5758 {
5759 5759 fc_local_port_t *port = port_handle;
5760 5760
5761 5761 mutex_enter(&port->fp_mutex);
5762 5762 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
5763 5763 mutex_exit(&port->fp_mutex);
5764 5764
5765 5765 fctl_idle_port(port);
5766 5766 }
5767 5767
5768 5768
5769 5769 static int
5770 5770 fctl_error(int fc_errno, char **errmsg)
5771 5771 {
5772 5772 int count;
5773 5773
5774 5774 for (count = 0; count < sizeof (fc_errlist) /
5775 5775 sizeof (fc_errlist[0]); count++) {
5776 5776 if (fc_errlist[count].fc_errno == fc_errno) {
5777 5777 *errmsg = fc_errlist[count].fc_errname;
5778 5778 return (FC_SUCCESS);
5779 5779 }
5780 5780 }
5781 5781 *errmsg = fctl_undefined;
5782 5782
5783 5783 return (FC_FAILURE);
5784 5784 }
5785 5785
5786 5786
5787 5787 /*
5788 5788 * Return number of successful translations.
5789 5789 * Anybody with some userland programming experience would have
5790 5790 * figured it by now that the return value exactly resembles that
5791 5791 * of scanf(3c). This function returns a count of successful
5792 5792 * translations. It could range from 0 (no match for state, reason,
5793 5793 * action, expln) to 4 (successful matches for all state, reason,
5794 5794 * action, expln) and where translation isn't successful into a
5795 5795 * friendlier message the relevent field is set to "Undefined"
5796 5796 */
5797 5797 static int
5798 5798 fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
5799 5799 char **action, char **expln)
5800 5800 {
5801 5801 int ret;
5802 5802 int len;
5803 5803 int index;
5804 5804 fc_pkt_error_t *error;
5805 5805 fc_pkt_reason_t *reason_b; /* Base pointer */
5806 5806 fc_pkt_action_t *action_b; /* Base pointer */
5807 5807 fc_pkt_expln_t *expln_b; /* Base pointer */
5808 5808
5809 5809 ret = 0;
5810 5810 *state = *reason = *action = *expln = fctl_undefined;
5811 5811
5812 5812 len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0];
5813 5813 for (index = 0; index < len; index++) {
5814 5814 error = fc_pkt_errlist + index;
5815 5815 if (pkt->pkt_state == error->pkt_state) {
5816 5816 *state = error->pkt_msg;
5817 5817 ret++;
5818 5818
5819 5819 reason_b = error->pkt_reason;
5820 5820 action_b = error->pkt_action;
5821 5821 expln_b = error->pkt_expln;
5822 5822
5823 5823 while (reason_b != NULL &&
5824 5824 reason_b->reason_val != FC_REASON_INVALID) {
5825 5825 if (reason_b->reason_val == pkt->pkt_reason) {
5826 5826 *reason = reason_b->reason_msg;
5827 5827 ret++;
5828 5828 break;
5829 5829 }
5830 5830 reason_b++;
5831 5831 }
5832 5832
5833 5833 while (action_b != NULL &&
5834 5834 action_b->action_val != FC_ACTION_INVALID) {
5835 5835 if (action_b->action_val == pkt->pkt_action) {
5836 5836 *action = action_b->action_msg;
5837 5837 ret++;
5838 5838 break;
5839 5839 }
5840 5840 action_b++;
5841 5841 }
5842 5842
5843 5843 while (expln_b != NULL &&
5844 5844 expln_b->expln_val != FC_EXPLN_INVALID) {
5845 5845 if (expln_b->expln_val == pkt->pkt_expln) {
5846 5846 *expln = expln_b->expln_msg;
5847 5847 ret++;
5848 5848 break;
5849 5849 }
5850 5850 expln_b++;
5851 5851 }
5852 5852 break;
5853 5853 }
5854 5854 }
5855 5855
5856 5856 return (ret);
5857 5857 }
5858 5858
5859 5859
5860 5860 /*
5861 5861 * Remove all port devices that are marked OLD, remove
5862 5862 * corresponding node devices (fc_remote_node_t)
5863 5863 */
5864 5864 void
5865 5865 fctl_remove_oldies(fc_local_port_t *port)
5866 5866 {
5867 5867 int index;
5868 5868 int initiator;
5869 5869 fc_remote_node_t *node;
5870 5870 struct pwwn_hash *head;
5871 5871 fc_remote_port_t *pd;
5872 5872 fc_remote_port_t *old_pd;
5873 5873 fc_remote_port_t *last_pd;
5874 5874
5875 5875 /*
5876 5876 * Nuke all OLD devices
5877 5877 */
5878 5878 mutex_enter(&port->fp_mutex);
5879 5879
5880 5880 for (index = 0; index < pwwn_table_size; index++) {
5881 5881 head = &port->fp_pwwn_table[index];
5882 5882 last_pd = NULL;
5883 5883 pd = head->pwwn_head;
5884 5884
5885 5885 while (pd != NULL) {
5886 5886 mutex_enter(&pd->pd_mutex);
5887 5887 if (pd->pd_type != PORT_DEVICE_OLD) {
5888 5888 mutex_exit(&pd->pd_mutex);
5889 5889 last_pd = pd;
5890 5890 pd = pd->pd_wwn_hnext;
5891 5891 continue;
5892 5892 }
5893 5893
5894 5894 /*
5895 5895 * Remove this from the PWWN hash table
5896 5896 */
5897 5897 old_pd = pd;
5898 5898 pd = old_pd->pd_wwn_hnext;
5899 5899
5900 5900 if (last_pd == NULL) {
5901 5901 ASSERT(old_pd == head->pwwn_head);
5902 5902 head->pwwn_head = pd;
5903 5903 } else {
5904 5904 last_pd->pd_wwn_hnext = pd;
5905 5905 }
5906 5906 head->pwwn_count--;
5907 5907 /*
5908 5908 * Make sure we tie fp_dev_count to the size of the
5909 5909 * pwwn_table
5910 5910 */
5911 5911 port->fp_dev_count--;
5912 5912 old_pd->pd_wwn_hnext = NULL;
5913 5913
5914 5914 fctl_delist_did_table(port, old_pd);
5915 5915 node = old_pd->pd_remote_nodep;
5916 5916 ASSERT(node != NULL);
5917 5917
5918 5918 initiator = (old_pd->pd_recepient ==
5919 5919 PD_PLOGI_INITIATOR) ? 1 : 0;
5920 5920
5921 5921 mutex_exit(&old_pd->pd_mutex);
5922 5922
5923 5923 if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) {
5924 5924 mutex_exit(&port->fp_mutex);
5925 5925
5926 5926 (void) fctl_add_orphan(port, old_pd,
5927 5927 KM_NOSLEEP);
5928 5928 } else {
5929 5929 mutex_exit(&port->fp_mutex);
5930 5930 }
5931 5931
5932 5932 if (fctl_destroy_remote_port(port, old_pd) == 0) {
5933 5933 if (node) {
5934 5934 fctl_destroy_remote_node(node);
5935 5935 }
5936 5936 }
5937 5937
5938 5938 mutex_enter(&port->fp_mutex);
5939 5939 }
5940 5940 }
5941 5941
5942 5942 mutex_exit(&port->fp_mutex);
5943 5943 }
5944 5944
5945 5945
5946 5946 static void
5947 5947 fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd)
5948 5948 {
5949 5949 ASSERT(MUTEX_HELD(&port->fp_mutex));
5950 5950 ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5951 5951
5952 5952 if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) {
5953 5953 return;
5954 5954 }
5955 5955
5956 5956 cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
5957 5957 port->fp_instance, pd->pd_port_id.port_id);
5958 5958 }
5959 5959
5960 5960
5961 5961 static int
5962 5962 fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa)
5963 5963 {
5964 5964 int index;
5965 5965
5966 5966 ASSERT(MUTEX_HELD(&port->fp_mutex));
5967 5967 ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5968 5968
5969 5969 for (index = 0; index < port->fp_lilp_map.lilp_length; index++) {
5970 5970 if (port->fp_lilp_map.lilp_alpalist[index] == alpa) {
5971 5971 return (FC_SUCCESS);
5972 5972 }
5973 5973 }
5974 5974
5975 5975 return (FC_FAILURE);
5976 5976 }
5977 5977
5978 5978
5979 5979 fc_remote_port_t *
5980 5980 fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
5981 5981 {
5982 5982 int index;
5983 5983 struct pwwn_hash *head;
5984 5984 fc_remote_port_t *pd;
5985 5985
5986 5986 ASSERT(MUTEX_HELD(&port->fp_mutex));
5987 5987
5988 5988 for (index = 0; index < pwwn_table_size; index++) {
5989 5989 head = &port->fp_pwwn_table[index];
5990 5990 pd = head->pwwn_head;
5991 5991
5992 5992 while (pd != NULL) {
5993 5993 mutex_enter(&pd->pd_mutex);
5994 5994 if (pd->pd_port_id.port_id == d_id) {
5995 5995 mutex_exit(&pd->pd_mutex);
5996 5996 return (pd);
5997 5997 }
5998 5998 mutex_exit(&pd->pd_mutex);
5999 5999 pd = pd->pd_wwn_hnext;
6000 6000 }
6001 6001 }
6002 6002
6003 6003 return (pd);
6004 6004 }
6005 6005
6006 6006
6007 6007 /*
6008 6008 * trace debugging
6009 6009 */
6010 6010 void
6011 6011 fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
6012 6012 int errno, const char *fmt, ...)
6013 6013 {
6014 6014 char buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
6015 6015 char *bufptr = buf;
6016 6016 va_list ap;
6017 6017 int cnt = 0;
6018 6018
6019 6019 if ((dlevel & dflag) == 0) {
6020 6020 return;
6021 6021 }
6022 6022
6023 6023 if (name) {
6024 6024 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
6025 6025 logq->il_id++, name);
6026 6026 } else {
6027 6027 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
6028 6028 logq->il_id++);
6029 6029 }
6030 6030
6031 6031 if (cnt < FC_MAX_TRACE_BUF_LEN) {
6032 6032 va_start(ap, fmt);
6033 6033 cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6034 6034 fmt, ap);
6035 6035 va_end(ap);
6036 6036 }
6037 6037
6038 6038 if (cnt > FC_MAX_TRACE_BUF_LEN) {
6039 6039 cnt = FC_MAX_TRACE_BUF_LEN;
6040 6040 }
6041 6041 if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) {
6042 6042 cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6043 6043 "error=0x%x\n", errno);
6044 6044 }
6045 6045 (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
6046 6046
6047 6047 if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) {
6048 6048 fc_trace_logmsg(logq, buf, dlevel);
6049 6049 }
6050 6050
6051 6051 /*
6052 6052 * We do not want to print the log numbers that appear as
6053 6053 * random numbers at the console and messages files, to
6054 6054 * the user.
6055 6055 */
6056 6056 if ((bufptr = strchr(buf, '>')) == NULL) {
6057 6057 /*
6058 6058 * We would have added the a string with "=>" above and so,
6059 6059 * ideally, we should not get here at all. But, if we do,
6060 6060 * we'll just use the full buf.
6061 6061 */
6062 6062 bufptr = buf;
6063 6063 } else {
6064 6064 bufptr++;
6065 6065 }
6066 6066
6067 6067 switch (dlevel & FC_TRACE_LOG_MASK) {
6068 6068 case FC_TRACE_LOG_CONSOLE:
6069 6069 cmn_err(CE_WARN, "%s", bufptr);
6070 6070 break;
6071 6071
6072 6072 case FC_TRACE_LOG_CONSOLE_MSG:
6073 6073 cmn_err(CE_WARN, "%s", bufptr);
6074 6074 break;
6075 6075
6076 6076 case FC_TRACE_LOG_MSG:
6077 6077 cmn_err(CE_WARN, "!%s", bufptr);
6078 6078 break;
6079 6079
6080 6080 default:
6081 6081 break;
6082 6082 }
6083 6083 }
6084 6084
6085 6085
6086 6086 /*
6087 6087 * This function can block
6088 6088 */
6089 6089 fc_trace_logq_t *
6090 6090 fc_trace_alloc_logq(int maxsize)
6091 6091 {
6092 6092 fc_trace_logq_t *logq;
6093 6093
6094 6094 logq = kmem_zalloc(sizeof (*logq), KM_SLEEP);
6095 6095
6096 6096 mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL);
6097 6097 logq->il_hiwat = maxsize;
6098 6098 logq->il_flags |= FC_TRACE_LOGQ_V2;
6099 6099
6100 6100 return (logq);
6101 6101 }
6102 6102
6103 6103
6104 6104 void
6105 6105 fc_trace_free_logq(fc_trace_logq_t *logq)
6106 6106 {
6107 6107 mutex_enter(&logq->il_lock);
6108 6108 while (logq->il_msgh) {
6109 6109 fc_trace_freemsg(logq);
6110 6110 }
6111 6111 mutex_exit(&logq->il_lock);
6112 6112
6113 6113 mutex_destroy(&logq->il_lock);
6114 6114 kmem_free(logq, sizeof (*logq));
6115 6115 }
6116 6116
6117 6117
6118 6118 /* ARGSUSED */
6119 6119 void
6120 6120 fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level)
6121 6121 {
6122 6122 int qfull = 0;
6123 6123 fc_trace_dmsg_t *dmsg;
6124 6124
6125 6125 dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP);
6126 6126 if (dmsg == NULL) {
6127 6127 mutex_enter(&logq->il_lock);
6128 6128 logq->il_afail++;
6129 6129 mutex_exit(&logq->il_lock);
6130 6130
6131 6131 return;
6132 6132 }
6133 6133
6134 6134 gethrestime(&dmsg->id_time);
6135 6135
6136 6136 dmsg->id_size = strlen(buf) + 1;
6137 6137 dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP);
6138 6138 if (dmsg->id_buf == NULL) {
6139 6139 kmem_free(dmsg, sizeof (*dmsg));
6140 6140
6141 6141 mutex_enter(&logq->il_lock);
6142 6142 logq->il_afail++;
6143 6143 mutex_exit(&logq->il_lock);
6144 6144
6145 6145 return;
6146 6146 }
6147 6147 bcopy(buf, dmsg->id_buf, strlen(buf));
6148 6148 dmsg->id_buf[strlen(buf)] = '\0';
6149 6149
6150 6150 mutex_enter(&logq->il_lock);
6151 6151
6152 6152 logq->il_size += dmsg->id_size;
6153 6153 if (logq->il_size >= logq->il_hiwat) {
6154 6154 qfull = 1;
6155 6155 }
6156 6156
6157 6157 if (qfull) {
6158 6158 fc_trace_freemsg(logq);
6159 6159 }
6160 6160
6161 6161 dmsg->id_next = NULL;
6162 6162 if (logq->il_msgt) {
6163 6163 logq->il_msgt->id_next = dmsg;
6164 6164 } else {
6165 6165 ASSERT(logq->il_msgh == NULL);
6166 6166 logq->il_msgh = dmsg;
6167 6167 }
6168 6168 logq->il_msgt = dmsg;
6169 6169
6170 6170 mutex_exit(&logq->il_lock);
6171 6171 }
6172 6172
6173 6173
6174 6174 static void
6175 6175 fc_trace_freemsg(fc_trace_logq_t *logq)
6176 6176 {
6177 6177 fc_trace_dmsg_t *dmsg;
6178 6178
6179 6179 ASSERT(MUTEX_HELD(&logq->il_lock));
6180 6180
6181 6181 if ((dmsg = logq->il_msgh) != NULL) {
6182 6182 logq->il_msgh = dmsg->id_next;
6183 6183 if (logq->il_msgh == NULL) {
6184 6184 logq->il_msgt = NULL;
6185 6185 }
6186 6186
6187 6187 logq->il_size -= dmsg->id_size;
6188 6188 kmem_free(dmsg->id_buf, dmsg->id_size);
6189 6189 kmem_free(dmsg, sizeof (*dmsg));
6190 6190 } else {
6191 6191 ASSERT(logq->il_msgt == NULL);
6192 6192 }
6193 6193 }
6194 6194
6195 6195 /*
6196 6196 * Used by T11 FC-HBA to fetch discovered ports by index.
6197 6197 * Returns NULL if the index isn't valid.
6198 6198 */
6199 6199 fc_remote_port_t *
6200 6200 fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
6201 6201 {
6202 6202 int outer;
6203 6203 int match = 0;
6204 6204 struct pwwn_hash *head;
6205 6205 fc_remote_port_t *pd;
6206 6206
6207 6207 ASSERT(MUTEX_HELD(&port->fp_mutex));
6208 6208
6209 6209 for (outer = 0;
6210 6210 outer < pwwn_table_size && match <= index;
6211 6211 outer++) {
6212 6212 head = &port->fp_pwwn_table[outer];
6213 6213 pd = head->pwwn_head;
6214 6214 if (pd != NULL) match ++;
6215 6215
6216 6216 while (pd != NULL && match <= index) {
6217 6217 pd = pd->pd_wwn_hnext;
6218 6218 if (pd != NULL) match ++;
6219 6219 }
6220 6220 }
6221 6221
6222 6222 return (pd);
6223 6223 }
6224 6224
6225 6225 /*
6226 6226 * Search for a matching Node or Port WWN in the discovered port list
6227 6227 */
6228 6228 fc_remote_port_t *
6229 6229 fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
6230 6230 {
6231 6231 int index;
6232 6232 struct pwwn_hash *head;
6233 6233 fc_remote_port_t *pd;
6234 6234
6235 6235 ASSERT(MUTEX_HELD(&port->fp_mutex));
6236 6236
6237 6237 for (index = 0; index < pwwn_table_size; index++) {
6238 6238 head = &port->fp_pwwn_table[index];
6239 6239 pd = head->pwwn_head;
6240 6240
6241 6241 while (pd != NULL) {
6242 6242 mutex_enter(&pd->pd_mutex);
6243 6243 if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
6244 6244 sizeof (la_wwn_t)) == 0) {
6245 6245 mutex_exit(&pd->pd_mutex);
6246 6246 return (pd);
6247 6247 }
6248 6248 if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn,
6249 6249 wwn.raw_wwn, sizeof (la_wwn_t)) == 0) {
6250 6250 mutex_exit(&pd->pd_mutex);
6251 6251 return (pd);
6252 6252 }
6253 6253 mutex_exit(&pd->pd_mutex);
6254 6254 pd = pd->pd_wwn_hnext;
6255 6255 }
6256 6256 }
6257 6257 /* No match */
6258 6258 return (NULL);
6259 6259 }
6260 6260
6261 6261
6262 6262 /*
6263 6263 * Count the number of ports on this adapter.
6264 6264 * This routine will walk the port list and count up the number of adapters
6265 6265 * with matching fp_hba_port_attrs.hba_fru_details.high and
6266 6266 * fp_hba_port_attrs.hba_fru_details.low.
6267 6267 *
6268 6268 * port->fp_mutex must not be held.
6269 6269 */
6270 6270 int
6271 6271 fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
6272 6272 {
6273 6273 fca_hba_fru_details_t *fru;
6274 6274 fc_fca_port_t *fca_port;
6275 6275 fc_local_port_t *tmpPort = NULL;
6276 6276 uint32_t count = 1;
6277 6277
6278 6278 mutex_enter(&fctl_port_lock);
6279 6279
6280 6280 mutex_enter(&port->fp_mutex);
6281 6281 fru = &port->fp_hba_port_attrs.hba_fru_details;
6282 6282
6283 6283 /* Detect FCA drivers that don't support linking HBA ports */
6284 6284 if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6285 6285 mutex_exit(&port->fp_mutex);
6286 6286 mutex_exit(&fctl_port_lock);
6287 6287 return (1);
6288 6288 }
6289 6289
6290 6290 for (fca_port = fctl_fca_portlist; fca_port != NULL;
6291 6291 fca_port = fca_port->port_next) {
6292 6292 tmpPort = fca_port->port_handle;
6293 6293 if (tmpPort == port) {
6294 6294 continue;
6295 6295 }
6296 6296 mutex_enter(&tmpPort->fp_mutex);
6297 6297
6298 6298 /*
6299 6299 * If an FCA driver returns unique fru->high and fru->low for
6300 6300 * ports on the same card, there is no way for the transport
6301 6301 * layer to determine that the two ports on the same FRU. So,
6302 6302 * the discovery of the ports on a same FRU is limited to what
6303 6303 * the FCA driver can report back.
6304 6304 */
6305 6305 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6306 6306 fru->high &&
6307 6307 tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6308 6308 fru->low) {
6309 6309 /* Now double check driver */
6310 6310 if (strncmp(port->fp_hba_port_attrs.driver_name,
6311 6311 tmpPort->fp_hba_port_attrs.driver_name,
6312 6312 FCHBA_DRIVER_NAME_LEN) == 0) {
6313 6313 if (!npivflag ||
6314 6314 (tmpPort->fp_npiv_type != FC_NPIV_PORT)) {
6315 6315 count++;
6316 6316 }
6317 6317 } /* Else, different FCA driver */
6318 6318 } /* Else not the same HBA FRU */
6319 6319 mutex_exit(&tmpPort->fp_mutex);
6320 6320 }
6321 6321
6322 6322 mutex_exit(&port->fp_mutex);
6323 6323 mutex_exit(&fctl_port_lock);
6324 6324
6325 6325 return (count);
6326 6326 }
6327 6327
6328 6328 fc_fca_port_t *
6329 6329 fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port)
6330 6330 {
6331 6331 fc_fca_port_t *tmp = list, *newentry = NULL;
6332 6332
6333 6333 newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP);
6334 6334 if (newentry == NULL) {
6335 6335 return (list);
6336 6336 }
6337 6337 newentry->port_handle = port;
6338 6338
6339 6339 if (tmp == NULL) {
6340 6340 return (newentry);
6341 6341 }
6342 6342 while (tmp->port_next != NULL) tmp = tmp->port_next;
6343 6343 tmp->port_next = newentry;
6344 6344
6345 6345 return (list);
6346 6346 }
6347 6347
6348 6348 void
6349 6349 fctl_local_port_list_free(fc_fca_port_t *list)
6350 6350 {
6351 6351 fc_fca_port_t *tmp = list, *nextentry;
6352 6352
6353 6353 if (tmp == NULL) {
6354 6354 return;
6355 6355 }
6356 6356
6357 6357 while (tmp != NULL) {
6358 6358 nextentry = tmp->port_next;
6359 6359 kmem_free(tmp, sizeof (*tmp));
6360 6360 tmp = nextentry;
6361 6361 }
6362 6362 }
6363 6363
6364 6364 /*
6365 6365 * Fetch another port on the HBA FRU based on index.
6366 6366 * Returns NULL if index not found.
6367 6367 *
6368 6368 * port->fp_mutex must not be held.
6369 6369 */
6370 6370 fc_local_port_t *
6371 6371 fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
6372 6372 {
6373 6373 fca_hba_fru_details_t *fru;
6374 6374 fc_fca_port_t *fca_port;
6375 6375 fc_local_port_t *tmpPort = NULL;
6376 6376 fc_fca_port_t *list = NULL, *tmpEntry;
6377 6377 fc_local_port_t *phyPort, *virPort = NULL;
6378 6378 int index, phyPortNum = 0;
6379 6379
6380 6380 mutex_enter(&fctl_port_lock);
6381 6381
6382 6382 mutex_enter(&port->fp_mutex);
6383 6383 fru = &port->fp_hba_port_attrs.hba_fru_details;
6384 6384
6385 6385 /* Are we looking for this port? */
6386 6386 if (fru->port_index == port_index) {
6387 6387 mutex_exit(&port->fp_mutex);
6388 6388 mutex_exit(&fctl_port_lock);
6389 6389 return (port);
6390 6390 }
6391 6391
6392 6392 /* Detect FCA drivers that don't support linking HBA ports */
6393 6393 if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6394 6394 mutex_exit(&port->fp_mutex);
6395 6395 mutex_exit(&fctl_port_lock);
6396 6396 return (NULL);
6397 6397 }
6398 6398
6399 6399 list = fctl_local_port_list_add(list, port);
6400 6400 phyPortNum++;
6401 6401 /* Loop through all known ports */
6402 6402 for (fca_port = fctl_fca_portlist; fca_port != NULL;
6403 6403 fca_port = fca_port->port_next) {
6404 6404 tmpPort = fca_port->port_handle;
6405 6405 if (tmpPort == port) {
6406 6406 /* Skip the port that was passed in as the argument */
6407 6407 continue;
6408 6408 }
6409 6409 mutex_enter(&tmpPort->fp_mutex);
6410 6410
6411 6411 /* See if this port is on the same HBA FRU (fast check) */
6412 6412 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6413 6413 fru->high &&
6414 6414 tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6415 6415 fru->low) {
6416 6416 /* Now double check driver (slower check) */
6417 6417 if (strncmp(port->fp_hba_port_attrs.driver_name,
6418 6418 tmpPort->fp_hba_port_attrs.driver_name,
6419 6419 FCHBA_DRIVER_NAME_LEN) == 0) {
6420 6420
6421 6421 fru =
6422 6422 &tmpPort->fp_hba_port_attrs.hba_fru_details;
6423 6423 /* Check for the matching port_index */
6424 6424 if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
6425 6425 (fru->port_index == port_index)) {
6426 6426 /* Found it! */
6427 6427 mutex_exit(&tmpPort->fp_mutex);
6428 6428 mutex_exit(&port->fp_mutex);
6429 6429 mutex_exit(&fctl_port_lock);
6430 6430 fctl_local_port_list_free(list);
6431 6431 return (tmpPort);
6432 6432 }
6433 6433 if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
6434 6434 (void) fctl_local_port_list_add(list,
6435 6435 tmpPort);
6436 6436 phyPortNum++;
6437 6437 }
6438 6438 } /* Else, different FCA driver */
6439 6439 } /* Else not the same HBA FRU */
6440 6440 mutex_exit(&tmpPort->fp_mutex);
6441 6441
6442 6442 }
6443 6443
6444 6444 /* scan all physical port on same chip to find virtual port */
6445 6445 tmpEntry = list;
6446 6446 index = phyPortNum - 1;
6447 6447 virPort = NULL;
6448 6448 while (index < port_index) {
6449 6449 if (tmpEntry == NULL) {
6450 6450 break;
6451 6451 }
6452 6452 if (virPort == NULL) {
6453 6453 phyPort = tmpEntry->port_handle;
6454 6454 virPort = phyPort->fp_port_next;
6455 6455 if (virPort == NULL) {
6456 6456 tmpEntry = tmpEntry->port_next;
6457 6457 continue;
6458 6458 }
6459 6459 } else {
6460 6460 virPort = virPort->fp_port_next;
6461 6461 }
6462 6462 if (virPort == phyPort) {
6463 6463 tmpEntry = tmpEntry->port_next;
6464 6464 virPort = NULL;
6465 6465 } else {
6466 6466 index++;
6467 6467 }
6468 6468 }
6469 6469 mutex_exit(&port->fp_mutex);
6470 6470 mutex_exit(&fctl_port_lock);
6471 6471
6472 6472 fctl_local_port_list_free(list);
6473 6473 if (virPort) {
6474 6474 return (virPort);
6475 6475 }
6476 6476 return (NULL);
6477 6477 }
6478 6478
6479 6479 int
6480 6480 fctl_busy_port(fc_local_port_t *port)
6481 6481 {
6482 6482 ASSERT(!MUTEX_HELD(&port->fp_mutex));
6483 6483
6484 6484 mutex_enter(&port->fp_mutex);
6485 6485 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
6486 6486 /*
6487 6487 * If fctl_busy_port() is called before we've registered our
6488 6488 * PM components, we return success. We need to be aware of
6489 6489 * this because the caller will eventually call fctl_idle_port.
6490 6490 * This wouldn't be a problem except that if we have
6491 6491 * registered our PM components in the meantime, we will
6492 6492 * then be idling a component that was never busied. PM
6493 6493 * will be very unhappy if we do this. Thus, we keep
6494 6494 * track of this with port->fp_pm_busy_nocomp.
6495 6495 */
6496 6496 port->fp_pm_busy_nocomp++;
6497 6497 mutex_exit(&port->fp_mutex);
6498 6498 return (0);
6499 6499 }
6500 6500 port->fp_pm_busy++;
6501 6501 mutex_exit(&port->fp_mutex);
6502 6502
6503 6503 if (pm_busy_component(port->fp_port_dip,
6504 6504 FP_PM_COMPONENT) != DDI_SUCCESS) {
6505 6505 mutex_enter(&port->fp_mutex);
6506 6506 port->fp_pm_busy--;
6507 6507 mutex_exit(&port->fp_mutex);
6508 6508 return (ENXIO);
6509 6509 }
6510 6510
6511 6511 mutex_enter(&port->fp_mutex);
6512 6512 if (port->fp_pm_level == FP_PM_PORT_DOWN) {
6513 6513 mutex_exit(&port->fp_mutex);
6514 6514 if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT,
6515 6515 FP_PM_PORT_UP) != DDI_SUCCESS) {
6516 6516
6517 6517 mutex_enter(&port->fp_mutex);
6518 6518 port->fp_pm_busy--;
6519 6519 mutex_exit(&port->fp_mutex);
6520 6520
6521 6521 (void) pm_idle_component(port->fp_port_dip,
6522 6522 FP_PM_COMPONENT);
6523 6523 return (EIO);
6524 6524 }
6525 6525 return (0);
6526 6526 }
6527 6527 mutex_exit(&port->fp_mutex);
6528 6528 return (0);
6529 6529 }
6530 6530
6531 6531 void
6532 6532 fctl_idle_port(fc_local_port_t *port)
6533 6533 {
6534 6534 ASSERT(!MUTEX_HELD(&port->fp_mutex));
6535 6535
6536 6536 mutex_enter(&port->fp_mutex);
6537 6537
6538 6538 /*
6539 6539 * If port->fp_pm_busy_nocomp is > 0, that means somebody had
6540 6540 * called fctl_busy_port prior to us registering our PM components.
6541 6541 * In that case, we just decrement fp_pm_busy_nocomp and return.
6542 6542 */
6543 6543
6544 6544 if (port->fp_pm_busy_nocomp > 0) {
6545 6545 port->fp_pm_busy_nocomp--;
6546 6546 mutex_exit(&port->fp_mutex);
6547 6547 return;
6548 6548 }
6549 6549
6550 6550 port->fp_pm_busy--;
6551 6551 mutex_exit(&port->fp_mutex);
6552 6552
6553 6553 (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT);
6554 6554 }
6555 6555
6556 6556 /*
6557 6557 * Function: fctl_tc_timer
6558 6558 *
6559 6559 * Description: Resets the value of the timed counter.
6560 6560 *
6561 6561 * Arguments: *tc Timed counter
6562 6562 *
6563 6563 * Return Value: Nothing
6564 6564 *
6565 6565 * Context: Kernel context.
6566 6566 */
6567 6567 static void
6568 6568 fctl_tc_timer(void *arg)
6569 6569 {
6570 6570 timed_counter_t *tc = (timed_counter_t *)arg;
6571 6571
6572 6572 ASSERT(tc != NULL);
6573 6573 ASSERT(tc->sig == tc);
6574 6574
6575 6575 mutex_enter(&tc->mutex);
6576 6576 if (tc->active) {
6577 6577 tc->active = B_FALSE;
6578 6578 tc->counter = 0;
6579 6579 }
6580 6580 mutex_exit(&tc->mutex);
6581 6581 }
6582 6582
6583 6583 /*
6584 6584 * Function: fctl_tc_constructor
6585 6585 *
6586 6586 * Description: Constructs a timed counter.
6587 6587 *
6588 6588 * Arguments: *tc Address where the timed counter will reside.
6589 6589 * max_value Maximum value the counter is allowed to take.
6590 6590 * timer Number of microseconds after which the counter
6591 6591 * will be reset. The timer is started when the
6592 6592 * value of the counter goes from 0 to 1.
6593 6593 *
6594 6594 * Return Value: Nothing
6595 6595 *
6596 6596 * Context: Kernel context.
6597 6597 */
6598 6598 void
6599 6599 fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer)
6600 6600 {
6601 6601 ASSERT(tc != NULL);
6602 6602 ASSERT(tc->sig != tc);
6603 6603
6604 6604 bzero(tc, sizeof (*tc));
6605 6605 mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL);
6606 6606 tc->timer = drv_usectohz(timer);
6607 6607 tc->active = B_FALSE;
6608 6608 tc->maxed_out = B_FALSE;
6609 6609 tc->max_value = max_value;
6610 6610 tc->sig = tc;
6611 6611 }
6612 6612
6613 6613 /*
6614 6614 * Function: fctl_tc_destructor
6615 6615 *
6616 6616 * Description: Destroyes a timed counter.
6617 6617 *
6618 6618 * Arguments: *tc Timed counter to destroy.
6619 6619 *
6620 6620 * Return Value: Nothing
6621 6621 *
6622 6622 * Context: Kernel context.
6623 6623 */
6624 6624 void
6625 6625 fctl_tc_destructor(timed_counter_t *tc)
6626 6626 {
6627 6627 ASSERT(tc != NULL);
6628 6628 ASSERT(tc->sig == tc);
6629 6629 ASSERT(!mutex_owned(&tc->mutex));
6630 6630
6631 6631 mutex_enter(&tc->mutex);
6632 6632 if (tc->active) {
6633 6633 tc->active = B_FALSE;
6634 6634 mutex_exit(&tc->mutex);
6635 6635 (void) untimeout(tc->tid);
6636 6636 mutex_enter(&tc->mutex);
6637 6637 tc->sig = NULL;
6638 6638 }
6639 6639 mutex_exit(&tc->mutex);
6640 6640 mutex_destroy(&tc->mutex);
6641 6641 }
6642 6642
6643 6643 /*
6644 6644 * Function: fctl_tc_increment
6645 6645 *
6646 6646 * Description: Increments a timed counter
6647 6647 *
6648 6648 * Arguments: *tc Timed counter to increment.
6649 6649 *
6650 6650 * Return Value: B_TRUE Counter reached the max value.
6651 6651 * B_FALSE Counter hasn't reached the max value.
6652 6652 *
6653 6653 * Context: Kernel or interrupt context.
6654 6654 */
6655 6655 boolean_t
6656 6656 fctl_tc_increment(timed_counter_t *tc)
6657 6657 {
6658 6658 ASSERT(tc != NULL);
6659 6659 ASSERT(tc->sig == tc);
6660 6660
6661 6661 mutex_enter(&tc->mutex);
6662 6662 if (!tc->maxed_out) {
6663 6663 /* Hasn't maxed out yet. */
6664 6664 ++tc->counter;
6665 6665 if (tc->counter >= tc->max_value) {
6666 6666 /* Just maxed out. */
6667 6667 tc->maxed_out = B_TRUE;
6668 6668 }
6669 6669 if (!tc->active) {
6670 6670 tc->tid = timeout(fctl_tc_timer, tc, tc->timer);
6671 6671 tc->active = B_TRUE;
6672 6672 }
6673 6673 }
6674 6674 mutex_exit(&tc->mutex);
6675 6675
6676 6676 return (tc->maxed_out);
6677 6677 }
6678 6678
6679 6679 /*
6680 6680 * Function: fctl_tc_reset
6681 6681 *
6682 6682 * Description: Resets a timed counter. The caller of this function has to
6683 6683 * to make sure that while in fctl_tc_reset() fctl_tc_increment()
6684 6684 * is not called.
6685 6685 *
6686 6686 * Arguments: *tc Timed counter to reset.
6687 6687 *
6688 6688 * Return Value: 0 Counter reached the max value.
6689 6689 * Not 0 Counter hasn't reached the max value.
6690 6690 *
6691 6691 * Context: Kernel or interrupt context.
6692 6692 */
6693 6693 void
6694 6694 fctl_tc_reset(timed_counter_t *tc)
6695 6695 {
6696 6696 ASSERT(tc != NULL);
6697 6697 ASSERT(tc->sig == tc);
6698 6698
6699 6699 mutex_enter(&tc->mutex);
6700 6700 tc->counter = 0;
6701 6701 tc->maxed_out = B_FALSE;
6702 6702 if (tc->active) {
6703 6703 tc->active = B_FALSE;
6704 6704 (void) untimeout(tc->tid);
6705 6705 }
6706 6706 mutex_exit(&tc->mutex);
6707 6707 }
6708 6708
6709 6709 void
6710 6710 fc_ulp_log_device_event(opaque_t port_handle, int type)
6711 6711 {
6712 6712 fc_local_port_t *port = port_handle;
6713 6713 nvlist_t *attr_list;
6714 6714
6715 6715 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
6716 6716 KM_SLEEP) != DDI_SUCCESS) {
6717 6717 return;
6718 6718 }
6719 6719
6720 6720 if (nvlist_add_uint32(attr_list, "instance",
6721 6721 port->fp_instance) != DDI_SUCCESS) {
6722 6722 goto error;
6723 6723 }
6724 6724
6725 6725 if (nvlist_add_byte_array(attr_list, "port-wwn",
6726 6726 port->fp_service_params.nport_ww_name.raw_wwn,
6727 6727 sizeof (la_wwn_t)) != DDI_SUCCESS) {
6728 6728 goto error;
6729 6729 }
6730 6730
6731 6731 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
6732 6732 (type == FC_ULP_DEVICE_ONLINE) ?
6733 6733 ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE,
6734 6734 attr_list, NULL, DDI_SLEEP);
6735 6735 nvlist_free(attr_list);
6736 6736 return;
6737 6737
6738 6738 error:
6739 6739 nvlist_free(attr_list);
6740 6740 }
↓ open down ↓ |
6073 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX