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