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