4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
29 * Fibre channel Transport Library (fctl)
31 * Function naming conventions:
32 * Functions called from ULPs begin with fc_ulp_
33 * Functions called from FCAs begin with fc_fca_
34 * Internal functions begin with fctl_
36 * Fibre channel packet layout:
37 * +---------------------+<--------+
39 * | ULP Packet private | |
41 * +---------------------+ |
43 * | struct fc_packet |---------+
45 * +---------------------+<--------+
47 * | FCA Packet private |
49 * +---------------------+
51 * So you loved the ascii art ? It's strongly desirable to cache
52 * allocate the entire packet in one common place. So we define a set a
53 * of rules. In a contiguous block of memory, the top portion of the
54 * block points to ulp packet private area, next follows the fc_packet
55 * structure used extensively by all the consumers and what follows this
56 * is the FCA packet private. Note that given a packet structure, it is
57 * possible to get to the ULP and FCA Packet private fields using
58 * ulp_private and fca_private fields (which hold pointers) respectively.
60 * It should be noted with a grain of salt that ULP Packet private size
61 * varies between two different ULP types, So this poses a challenge to
62 * compute the correct size of the whole block on a per port basis. The
63 * transport layer doesn't have a problem in dealing with FCA packet
64 * private sizes as it is the sole manager of ports underneath. Since
65 * it's not a good idea to cache allocate different sizes of memory for
66 * different ULPs and have the ability to choose from one of these caches
67 * based on ULP type during every packet allocation, the transport some
68 * what wisely (?) hands off this job of cache allocation to the ULPs
71 * That means FCAs need to make their packet private size known to the
72 * transport to pass it up to the ULPs. This is done during
73 * fc_fca_attach(). And the transport passes this size up to ULPs during
74 * fc_ulp_port_attach() of each ULP.
76 * This leaves us with another possible question; How are packets
77 * allocated for ELS's started by the transport itself ? Well, the port
78 * driver during attach time, cache allocates on a per port basis to
83 #include <sys/types.h>
84 #include <sys/varargs.h>
85 #include <sys/param.h>
86 #include <sys/errno.h>
89 #include <sys/modctl.h>
94 #include <sys/cmn_err.h>
97 #include <sys/sunddi.h>
98 #include <sys/promif.h>
99 #include <sys/byteorder.h>
100 #include <sys/fibre-channel/fc.h>
101 #include <sys/fibre-channel/impl/fc_ulpif.h>
102 #include <sys/fibre-channel/impl/fc_fcaif.h>
103 #include <sys/fibre-channel/impl/fctl_private.h>
104 #include <sys/fibre-channel/impl/fc_portif.h>
106 /* These are referenced by fp.c! */
107 int did_table_size
= D_ID_HASH_TABLE_SIZE
;
108 int pwwn_table_size
= PWWN_HASH_TABLE_SIZE
;
110 static fc_ulp_module_t
*fctl_ulp_modules
;
111 static fc_fca_port_t
*fctl_fca_portlist
;
112 static fc_ulp_list_t
*fctl_ulp_list
;
114 static char fctl_greeting
[] =
115 "fctl: %s ULP same type (0x%x) as existing module.\n";
117 static char *fctl_undefined
= "Undefined";
120 * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
123 static krwlock_t fctl_ulp_lock
;
126 * The fctl_mod_ports_lock protects the mod_ports element in the
127 * fc_ulp_ports_t structure
130 static krwlock_t fctl_mod_ports_lock
;
133 * fctl_port_lock protects the linked list of local port structures
134 * (fctl_fca_portlist). When walking the list, this lock must be obtained
135 * prior to any local port locks.
138 static kmutex_t fctl_port_lock
;
139 static kmutex_t fctl_ulp_list_mutex
;
141 static fctl_nwwn_list_t
*fctl_nwwn_hash_table
;
142 static kmutex_t fctl_nwwn_hash_mutex
;
143 int fctl_nwwn_table_size
= NWWN_HASH_TABLE_SIZE
;
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
))
156 #define FCTL_VERSION "20090729-1.70"
157 #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION
159 char *fctl_version
= FCTL_NAME_VERSION
;
161 extern struct mod_ops mod_miscops
;
163 static struct modlmisc modlmisc
= {
164 &mod_miscops
, /* type of module */
165 FCTL_NAME_VERSION
/* Module name */
168 static struct modlinkage modlinkage
= {
169 MODREV_1
, (void *)&modlmisc
, NULL
172 static struct bus_ops fctl_fca_busops
= {
174 nullbusmap
, /* bus_map */
175 NULL
, /* bus_get_intrspec */
176 NULL
, /* bus_add_intrspec */
177 NULL
, /* bus_remove_intrspec */
178 i_ddi_map_fault
, /* bus_map_fault */
179 NULL
, /* bus_dma_map */
180 ddi_dma_allochdl
, /* bus_dma_allochdl */
181 ddi_dma_freehdl
, /* bus_dma_freehdl */
182 ddi_dma_bindhdl
, /* bus_dma_bindhdl */
183 ddi_dma_unbindhdl
, /* bus_unbindhdl */
184 ddi_dma_flush
, /* bus_dma_flush */
185 ddi_dma_win
, /* bus_dma_win */
186 ddi_dma_mctl
, /* bus_dma_ctl */
187 fctl_fca_bus_ctl
, /* bus_ctl */
188 ddi_bus_prop_op
, /* bus_prop_op */
189 NULL
, /* bus_get_eventcookie */
190 NULL
, /* bus_add_eventcall */
191 NULL
, /* bus_remove_event */
192 NULL
, /* bus_post_event */
193 NULL
, /* bus_intr_ctl */
194 NULL
, /* bus_config */
195 NULL
, /* bus_unconfig */
196 NULL
, /* bus_fm_init */
197 NULL
, /* bus_fm_fini */
198 NULL
, /* bus_fm_access_enter */
199 NULL
, /* bus_fm_access_exit */
200 NULL
, /* bus_power */
204 struct kmem_cache
*fctl_job_cache
;
206 static fc_errmap_t fc_errlist
[] = {
207 { FC_FAILURE
, "Operation failed" },
208 { FC_SUCCESS
, "Operation success" },
209 { FC_CAP_ERROR
, "Capability error" },
210 { FC_CAP_FOUND
, "Capability found" },
211 { FC_CAP_SETTABLE
, "Capability settable" },
212 { FC_UNBOUND
, "Port not bound" },
213 { FC_NOMEM
, "No memory" },
214 { FC_BADPACKET
, "Bad packet" },
215 { FC_OFFLINE
, "Port offline" },
216 { FC_OLDPORT
, "Old Port" },
217 { FC_NO_MAP
, "No map available" },
218 { FC_TRANSPORT_ERROR
, "Transport error" },
219 { FC_ELS_FREJECT
, "ELS Frejected" },
220 { FC_ELS_PREJECT
, "ELS PRejected" },
221 { FC_ELS_BAD
, "Bad ELS request" },
222 { FC_ELS_MALFORMED
, "Malformed ELS request" },
223 { FC_TOOMANY
, "Too many commands" },
224 { FC_UB_BADTOKEN
, "Bad Unsolicited buffer token" },
225 { FC_UB_ERROR
, "Unsolicited buffer error" },
226 { FC_UB_BUSY
, "Unsolicited buffer busy" },
227 { FC_BADULP
, "Bad ULP" },
228 { FC_BADTYPE
, "Bad Type" },
229 { FC_UNCLAIMED
, "Not Claimed" },
230 { FC_ULP_SAMEMODULE
, "Same ULP Module" },
231 { FC_ULP_SAMETYPE
, "Same ULP Type" },
232 { FC_ABORTED
, "Command Aborted" },
233 { FC_ABORT_FAILED
, "Abort Failed" },
234 { FC_BADEXCHANGE
, "Bad Exchange" },
235 { FC_BADWWN
, "Bad World Wide Name" },
236 { FC_BADDEV
, "Bad Device" },
237 { FC_BADCMD
, "Bad Command" },
238 { FC_BADOBJECT
, "Bad Object" },
239 { FC_BADPORT
, "Bad Port" },
240 { FC_NOTTHISPORT
, "Not on this Port" },
241 { FC_PREJECT
, "Operation Prejected" },
242 { FC_FREJECT
, "Operation Frejected" },
243 { FC_PBUSY
, "Operation Pbusyed" },
244 { FC_FBUSY
, "Operation Fbusyed" },
245 { FC_ALREADY
, "Already done" },
246 { FC_LOGINREQ
, "PLOGI Required" },
247 { FC_RESETFAIL
, "Reset operation failed" },
248 { FC_INVALID_REQUEST
, "Invalid Request" },
249 { FC_OUTOFBOUNDS
, "Out of Bounds" },
250 { FC_TRAN_BUSY
, "Command transport Busy" },
251 { FC_STATEC_BUSY
, "State change Busy" },
252 { FC_DEVICE_BUSY
, "Port driver is working on this device" }
255 fc_pkt_reason_t remote_stop_reasons
[] = {
256 { FC_REASON_ABTS
, "Abort Sequence" },
257 { FC_REASON_ABTX
, "Abort Exchange" },
258 { FC_REASON_INVALID
, NULL
}
261 fc_pkt_reason_t general_reasons
[] = {
262 { FC_REASON_HW_ERROR
, "Hardware Error" },
263 { FC_REASON_SEQ_TIMEOUT
, "Sequence Timeout" },
264 { FC_REASON_ABORTED
, "Aborted" },
265 { FC_REASON_ABORT_FAILED
, "Abort Failed" },
266 { FC_REASON_NO_CONNECTION
, "No Connection" },
267 { FC_REASON_XCHG_DROPPED
, "Exchange Dropped" },
268 { FC_REASON_ILLEGAL_FRAME
, "Illegal Frame" },
269 { FC_REASON_ILLEGAL_LENGTH
, "Illegal Length" },
270 { FC_REASON_UNSUPPORTED
, "Unsuported" },
271 { FC_REASON_RX_BUF_TIMEOUT
, "Receive Buffer Timeout" },
272 { FC_REASON_FCAL_OPN_FAIL
, "FC AL Open Failed" },
273 { FC_REASON_OVERRUN
, "Over run" },
274 { FC_REASON_QFULL
, "Queue Full" },
275 { FC_REASON_ILLEGAL_REQ
, "Illegal Request", },
276 { FC_REASON_PKT_BUSY
, "Busy" },
277 { FC_REASON_OFFLINE
, "Offline" },
278 { FC_REASON_BAD_XID
, "Bad Exchange Id" },
279 { FC_REASON_XCHG_BSY
, "Exchange Busy" },
280 { FC_REASON_NOMEM
, "No Memory" },
281 { FC_REASON_BAD_SID
, "Bad S_ID" },
282 { FC_REASON_NO_SEQ_INIT
, "No Sequence Initiative" },
283 { FC_REASON_DIAG_BUSY
, "Diagnostic Busy" },
284 { FC_REASON_DMA_ERROR
, "DMA Error" },
285 { FC_REASON_CRC_ERROR
, "CRC Error" },
286 { FC_REASON_ABORT_TIMEOUT
, "Abort Timeout" },
287 { FC_REASON_FCA_UNIQUE
, "FCA Unique" },
288 { FC_REASON_INVALID
, NULL
}
291 fc_pkt_reason_t rjt_reasons
[] = {
292 { FC_REASON_INVALID_D_ID
, "Invalid D_ID" },
293 { FC_REASON_INVALID_S_ID
, "Invalid S_ID" },
294 { FC_REASON_TEMP_UNAVAILABLE
, "Temporarily Unavailable" },
295 { FC_REASON_PERM_UNAVAILABLE
, "Permamnently Unavailable" },
296 { FC_REASON_CLASS_NOT_SUPP
, "Class Not Supported", },
297 { FC_REASON_DELIMTER_USAGE_ERROR
,
298 "Delimeter Usage Error" },
299 { FC_REASON_TYPE_NOT_SUPP
, "Type Not Supported" },
300 { FC_REASON_INVALID_LINK_CTRL
, "Invalid Link Control" },
301 { FC_REASON_INVALID_R_CTL
, "Invalid R_CTL" },
302 { FC_REASON_INVALID_F_CTL
, "Invalid F_CTL" },
303 { FC_REASON_INVALID_OX_ID
, "Invalid OX_ID" },
304 { FC_REASON_INVALID_RX_ID
, "Invalid RX_ID" },
305 { FC_REASON_INVALID_SEQ_ID
, "Invalid Sequence ID" },
306 { FC_REASON_INVALID_DF_CTL
, "Invalid DF_CTL" },
307 { FC_REASON_INVALID_SEQ_CNT
, "Invalid Sequence count" },
308 { FC_REASON_INVALID_PARAM
, "Invalid Parameter" },
309 { FC_REASON_EXCH_ERROR
, "Exchange Error" },
310 { FC_REASON_PROTOCOL_ERROR
, "Protocol Error" },
311 { FC_REASON_INCORRECT_LENGTH
, "Incorrect Length" },
312 { FC_REASON_UNEXPECTED_ACK
, "Unexpected Ack" },
313 { FC_REASON_UNEXPECTED_LR
, "Unexpected Link reset" },
314 { FC_REASON_LOGIN_REQUIRED
, "Login Required" },
315 { FC_REASON_EXCESSIVE_SEQS
, "Excessive Sequences"
317 { FC_REASON_EXCH_UNABLE
, "Exchange incapable" },
318 { FC_REASON_ESH_NOT_SUPP
, "Expiration Security Header "
320 { FC_REASON_NO_FABRIC_PATH
, "No Fabric Path" },
321 { FC_REASON_VENDOR_UNIQUE
, "Vendor Unique" },
322 { FC_REASON_INVALID
, NULL
}
325 fc_pkt_reason_t n_port_busy_reasons
[] = {
326 { FC_REASON_PHYSICAL_BUSY
, "Physical Busy" },
327 { FC_REASON_N_PORT_RESOURCE_BSY
, "Resource Busy" },
328 { FC_REASON_N_PORT_VENDOR_UNIQUE
, "Vendor Unique" },
329 { FC_REASON_INVALID
, NULL
}
332 fc_pkt_reason_t f_busy_reasons
[] = {
333 { FC_REASON_FABRIC_BSY
, "Fabric Busy" },
334 { FC_REASON_N_PORT_BSY
, "N_Port Busy" },
335 { FC_REASON_INVALID
, NULL
}
338 fc_pkt_reason_t ls_ba_rjt_reasons
[] = {
339 { FC_REASON_INVALID_LA_CODE
, "Invalid Link Application Code" },
340 { FC_REASON_LOGICAL_ERROR
, "Logical Error" },
341 { FC_REASON_LOGICAL_BSY
, "Logical Busy" },
342 { FC_REASON_PROTOCOL_ERROR_RJT
, "Protocol Error Reject" },
343 { FC_REASON_CMD_UNABLE
, "Unable to Perform Command" },
344 { FC_REASON_CMD_UNSUPPORTED
, "Unsupported Command" },
345 { FC_REASON_VU_RJT
, "Vendor Unique" },
346 { FC_REASON_INVALID
, NULL
}
349 fc_pkt_reason_t fs_rjt_reasons
[] = {
350 { FC_REASON_FS_INVALID_CMD
, "Invalid Command" },
351 { FC_REASON_FS_INVALID_VER
, "Invalid Version" },
352 { FC_REASON_FS_LOGICAL_ERR
, "Logical Error" },
353 { FC_REASON_FS_INVALID_IUSIZE
, "Invalid IU Size" },
354 { FC_REASON_FS_LOGICAL_BUSY
, "Logical Busy" },
355 { FC_REASON_FS_PROTOCOL_ERR
, "Protocol Error" },
356 { FC_REASON_FS_CMD_UNABLE
, "Unable to Perform Command" },
357 { FC_REASON_FS_CMD_UNSUPPORTED
, "Unsupported Command" },
358 { FC_REASON_FS_VENDOR_UNIQUE
, "Vendor Unique" },
359 { FC_REASON_INVALID
, NULL
}
362 fc_pkt_action_t n_port_busy_actions
[] = {
363 { FC_ACTION_SEQ_TERM_RETRY
, "Retry terminated Sequence" },
364 { FC_ACTION_SEQ_ACTIVE_RETRY
, "Retry Active Sequence" },
365 { FC_REASON_INVALID
, NULL
}
368 fc_pkt_action_t rjt_timeout_actions
[] = {
369 { FC_ACTION_RETRYABLE
, "Retryable" },
370 { FC_ACTION_NON_RETRYABLE
, "Non Retryable" },
371 { FC_REASON_INVALID
, NULL
}
374 fc_pkt_expln_t ba_rjt_explns
[] = {
375 { FC_EXPLN_NONE
, "No Explanation" },
376 { FC_EXPLN_INVALID_OX_RX_ID
, "Invalid X_ID" },
377 { FC_EXPLN_SEQ_ABORTED
, "Sequence Aborted" },
378 { FC_EXPLN_INVALID
, NULL
}
381 fc_pkt_error_t fc_pkt_errlist
[] = {
389 { FC_PKT_REMOTE_STOP
,
446 "Link Service Reject",
467 "Fabric Switch Reject",
474 "Packet Transport error",
494 FC_PKT_ELS_IN_PROGRESS
,
495 "ELS is in Progress",
507 rw_init(&fctl_ulp_lock
, NULL
, RW_DRIVER
, NULL
);
508 rw_init(&fctl_mod_ports_lock
, NULL
, RW_DRIVER
, NULL
);
509 mutex_init(&fctl_port_lock
, NULL
, MUTEX_DRIVER
, NULL
);
510 mutex_init(&fctl_nwwn_hash_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
512 fctl_nwwn_hash_table
= kmem_zalloc(sizeof (*fctl_nwwn_hash_table
) *
513 fctl_nwwn_table_size
, KM_SLEEP
);
515 fctl_ulp_modules
= NULL
;
516 fctl_fca_portlist
= NULL
;
518 fctl_job_cache
= kmem_cache_create("fctl_cache",
519 sizeof (job_request_t
), 8, fctl_cache_constructor
,
520 fctl_cache_destructor
, NULL
, NULL
, NULL
, 0);
522 if (fctl_job_cache
== NULL
) {
523 kmem_free(fctl_nwwn_hash_table
,
524 sizeof (*fctl_nwwn_hash_table
) * fctl_nwwn_table_size
);
525 mutex_destroy(&fctl_nwwn_hash_mutex
);
526 mutex_destroy(&fctl_port_lock
);
527 rw_destroy(&fctl_ulp_lock
);
528 rw_destroy(&fctl_mod_ports_lock
);
532 if ((rval
= mod_install(&modlinkage
)) != 0) {
533 kmem_cache_destroy(fctl_job_cache
);
534 kmem_free(fctl_nwwn_hash_table
,
535 sizeof (*fctl_nwwn_hash_table
) * fctl_nwwn_table_size
);
536 mutex_destroy(&fctl_nwwn_hash_mutex
);
537 mutex_destroy(&fctl_port_lock
);
538 rw_destroy(&fctl_ulp_lock
);
539 rw_destroy(&fctl_mod_ports_lock
);
547 * The mod_uninstall code doesn't call _fini when
548 * there is living dependent module on fctl. So
549 * there is no need to be extra careful here ?
556 if ((rval
= mod_remove(&modlinkage
)) != 0) {
560 kmem_cache_destroy(fctl_job_cache
);
561 kmem_free(fctl_nwwn_hash_table
,
562 sizeof (*fctl_nwwn_hash_table
) * fctl_nwwn_table_size
);
563 mutex_destroy(&fctl_nwwn_hash_mutex
);
564 mutex_destroy(&fctl_port_lock
);
565 rw_destroy(&fctl_ulp_lock
);
566 rw_destroy(&fctl_mod_ports_lock
);
573 _info(struct modinfo
*modinfo_p
)
575 return (mod_info(&modlinkage
, modinfo_p
));
581 fctl_cache_constructor(void *buf
, void *cdarg
, int kmflag
)
583 job_request_t
*job
= (job_request_t
*)buf
;
585 mutex_init(&job
->job_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
586 sema_init(&job
->job_fctl_sema
, 0, NULL
, SEMA_DEFAULT
, NULL
);
587 sema_init(&job
->job_port_sema
, 0, NULL
, SEMA_DEFAULT
, NULL
);
595 fctl_cache_destructor(void *buf
, void *cdarg
)
597 job_request_t
*job
= (job_request_t
*)buf
;
599 sema_destroy(&job
->job_fctl_sema
);
600 sema_destroy(&job
->job_port_sema
);
601 mutex_destroy(&job
->job_mutex
);
614 * fc_ulp_add prints a warning message if there is already a
615 * similar ULP type attached and this is unlikely to change as
616 * we trudge along. Further, this function returns a failure
617 * code if the same module attempts to add more than once for
618 * the same FC-4 type.
621 fc_ulp_add(fc_ulp_modinfo_t
*ulp_info
)
623 fc_ulp_module_t
*mod
;
624 fc_ulp_module_t
*prev
;
627 fc_fca_port_t
*fca_port
;
630 ASSERT(ulp_info
!= NULL
);
633 * Make sure ulp_rev matches fctl version.
634 * Whenever non-private data structure or non-static interface changes,
635 * we should use an increased FCTL_ULP_MODREV_# number here and in all
636 * ulps to prevent version mismatch.
638 if (ulp_info
->ulp_rev
!= FCTL_ULP_MODREV_4
) {
639 cmn_err(CE_WARN
, "fctl: ULP %s version mismatch;"
640 " ULP %s would not be loaded", ulp_info
->ulp_name
,
645 new = kmem_zalloc(sizeof (*new), KM_SLEEP
);
648 mutex_enter(&fctl_ulp_list_mutex
);
649 new->ulp_info
= ulp_info
;
650 if (fctl_ulp_list
!= NULL
) {
651 new->ulp_next
= fctl_ulp_list
;
654 mutex_exit(&fctl_ulp_list_mutex
);
656 while (rw_tryenter(&fctl_ulp_lock
, RW_WRITER
) == 0) {
657 delay(drv_usectohz(1000000));
658 if (ntry
++ > FC_ULP_ADD_RETRY_COUNT
) {
661 mutex_enter(&fctl_ulp_list_mutex
);
662 for (last
= NULL
, list
= fctl_ulp_list
; list
!= NULL
;
663 list
= list
->ulp_next
) {
664 if (list
->ulp_info
== ulp_info
) {
672 last
->ulp_next
= list
->ulp_next
;
674 fctl_ulp_list
= list
->ulp_next
;
676 kmem_free(list
, sizeof (*list
));
678 mutex_exit(&fctl_ulp_list_mutex
);
679 cmn_err(CE_WARN
, "fctl: ULP %s unable to load",
685 for (mod
= fctl_ulp_modules
, prev
= NULL
; mod
; mod
= mod
->mod_next
) {
686 ASSERT(mod
->mod_info
!= NULL
);
688 if (ulp_info
== mod
->mod_info
&&
689 ulp_info
->ulp_type
== mod
->mod_info
->ulp_type
) {
690 rw_exit(&fctl_ulp_lock
);
691 return (FC_ULP_SAMEMODULE
);
694 if (ulp_info
->ulp_type
== mod
->mod_info
->ulp_type
) {
695 cmn_err(CE_NOTE
, fctl_greeting
, ulp_info
->ulp_name
,
701 mod
= kmem_zalloc(sizeof (*mod
), KM_SLEEP
);
702 mod
->mod_info
= ulp_info
;
703 mod
->mod_next
= NULL
;
706 prev
->mod_next
= mod
;
708 fctl_ulp_modules
= mod
;
712 * Schedule a job to each port's job_handler
713 * thread to attach their ports with this ULP.
715 mutex_enter(&fctl_port_lock
);
716 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
717 fca_port
= fca_port
->port_next
) {
718 job
= fctl_alloc_job(JOB_ATTACH_ULP
, JOB_TYPE_FCTL_ASYNC
,
719 NULL
, NULL
, KM_SLEEP
);
721 fctl_enque_job(fca_port
->port_handle
, job
);
723 mutex_exit(&fctl_port_lock
);
725 rw_exit(&fctl_ulp_lock
);
733 * Remove a ULP module
735 * A misbehaving ULP may call this routine while I/Os are in progress.
736 * Currently there is no mechanism to detect it to fail such a request.
743 fc_ulp_remove(fc_ulp_modinfo_t
*ulp_info
)
745 fc_ulp_module_t
*mod
;
748 fc_ulp_module_t
*prev
;
750 mutex_enter(&fctl_ulp_list_mutex
);
752 for (last
= NULL
, list
= fctl_ulp_list
; list
!= NULL
;
753 list
= list
->ulp_next
) {
754 if (list
->ulp_info
== ulp_info
) {
762 last
->ulp_next
= list
->ulp_next
;
764 fctl_ulp_list
= list
->ulp_next
;
766 kmem_free(list
, sizeof (*list
));
769 mutex_exit(&fctl_ulp_list_mutex
);
771 rw_enter(&fctl_ulp_lock
, RW_WRITER
);
773 for (mod
= fctl_ulp_modules
, prev
= NULL
; mod
!= NULL
;
774 mod
= mod
->mod_next
) {
775 if (mod
->mod_info
== ulp_info
) {
782 fc_ulp_ports_t
*next
;
785 prev
->mod_next
= mod
->mod_next
;
787 fctl_ulp_modules
= mod
->mod_next
;
790 rw_enter(&fctl_mod_ports_lock
, RW_WRITER
);
792 while ((next
= mod
->mod_ports
) != NULL
) {
793 mod
->mod_ports
= next
->port_next
;
794 fctl_dealloc_ulp_port(next
);
797 rw_exit(&fctl_mod_ports_lock
);
798 rw_exit(&fctl_ulp_lock
);
800 kmem_free(mod
, sizeof (*mod
));
804 rw_exit(&fctl_ulp_lock
);
811 * The callers typically cache allocate the packet, complete the
812 * DMA setup for pkt_cmd and pkt_resp fields of the packet and
813 * call this function to see if the FCA is interested in doing
814 * its own intialization. For example, socal may like to initialize
815 * the soc_hdr which is pointed to by the pkt_fca_private field
816 * and sitting right below fc_packet_t in memory.
818 * The caller is required to ensure that pkt_pd is populated with the
819 * handle that it was given when the transport notified it about the
820 * device this packet is associated with. If there is no associated
821 * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an
822 * increment of the reference count for said pd. When the packet is freed,
823 * the reference count will be decremented. This reference count, in
824 * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
825 * will not wink out of existence while there is a packet outstanding.
827 * This function and fca_init_pkt must not perform any operations that
828 * would result in a call back to the ULP, as the ULP may be required
829 * to hold a mutex across this call to ensure that the pd in question
830 * won't go away prior the call to fc_ulp_transport.
832 * ULPs are responsible for using the handles they are given during state
833 * change callback processing in a manner that ensures consistency. That
834 * is, they must be aware that they could be processing a state change
835 * notification that tells them the device associated with a particular
836 * handle has gone away at the same time they are being asked to
837 * initialize a packet using that handle. ULPs must therefore ensure
838 * that their state change processing and packet initialization code
839 * paths are sufficiently synchronized to avoid the use of an
840 * invalidated handle in any fc_packet_t struct that is passed to the
841 * fc_ulp_init_packet() function.
844 fc_ulp_init_packet(opaque_t port_handle
, fc_packet_t
*pkt
, int sleep
)
847 fc_local_port_t
*port
= port_handle
;
848 fc_remote_port_t
*pd
;
854 /* Call the FCA driver's fca_init_pkt entry point function. */
855 rval
= port
->fp_fca_tran
->fca_init_pkt(port
->fp_fca_handle
, pkt
, sleep
);
857 if ((rval
== FC_SUCCESS
) && (pd
!= NULL
)) {
859 * A !NULL pd here must still be a valid
860 * reference to the fc_remote_port_t.
862 mutex_enter(&pd
->pd_mutex
);
863 ASSERT(pd
->pd_ref_count
>= 0);
865 mutex_exit(&pd
->pd_mutex
);
873 * This function is called before destroying the cache allocated
874 * fc_packet to free up (and uninitialize) any resource specially
875 * allocated by the FCA driver during tran_init_pkt().
877 * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
878 * the pd_ref_count reference count is decremented for the indicated
879 * fc_remote_port_t struct.
882 fc_ulp_uninit_packet(opaque_t port_handle
, fc_packet_t
*pkt
)
885 fc_local_port_t
*port
= port_handle
;
886 fc_remote_port_t
*pd
;
892 /* Call the FCA driver's fca_un_init_pkt entry point function */
893 rval
= port
->fp_fca_tran
->fca_un_init_pkt(port
->fp_fca_handle
, pkt
);
895 if ((rval
== FC_SUCCESS
) && (pd
!= NULL
)) {
896 mutex_enter(&pd
->pd_mutex
);
898 ASSERT(pd
->pd_ref_count
> 0);
902 * If at this point the state of this fc_remote_port_t
903 * struct is PORT_DEVICE_INVALID, it probably means somebody
904 * is cleaning up old (e.g. retried) packets. If the
905 * pd_ref_count has also dropped to zero, it's time to
906 * deallocate this fc_remote_port_t struct.
908 if (pd
->pd_state
== PORT_DEVICE_INVALID
&&
909 pd
->pd_ref_count
== 0) {
910 fc_remote_node_t
*node
= pd
->pd_remote_nodep
;
912 mutex_exit(&pd
->pd_mutex
);
915 * Also deallocate the associated fc_remote_node_t
916 * struct if it has no other associated
917 * fc_remote_port_t structs.
919 if ((fctl_destroy_remote_port(port
, pd
) == 0) &&
921 fctl_destroy_remote_node(node
);
926 mutex_exit(&pd
->pd_mutex
);
934 fc_ulp_getportmap(opaque_t port_handle
, fc_portmap_t
**map
, uint32_t *len
,
938 fc_local_port_t
*port
;
940 fc_portmap_t
*tmp_map
;
942 fc_portmap_t
*change_list
= NULL
;
943 uint32_t listlen
= 0;
947 mutex_enter(&port
->fp_mutex
);
948 if (port
->fp_statec_busy
) {
949 mutex_exit(&port
->fp_mutex
);
950 return (FC_STATEC_BUSY
);
953 if (FC_PORT_STATE_MASK(port
->fp_state
) == FC_STATE_OFFLINE
) {
954 mutex_exit(&port
->fp_mutex
);
958 if (port
->fp_dev_count
&& (port
->fp_dev_count
==
959 port
->fp_total_devices
)) {
960 mutex_exit(&port
->fp_mutex
);
961 fctl_fillout_map(port
, &change_list
, &listlen
, 1, 1, 0);
962 if (listlen
> *len
) {
963 tmp_map
= (fc_portmap_t
*)kmem_zalloc(
964 listlen
* sizeof (fc_portmap_t
), KM_NOSLEEP
);
965 if (tmp_map
== NULL
) {
969 kmem_free(*map
, (*len
) * sizeof (fc_portmap_t
));
974 bcopy(change_list
, *map
,
975 listlen
* sizeof (fc_portmap_t
));
976 kmem_free(change_list
, listlen
* sizeof (fc_portmap_t
));
980 mutex_exit(&port
->fp_mutex
);
983 case FC_ULP_PLOGI_DONTCARE
:
984 job_code
= JOB_PORT_GETMAP
;
987 case FC_ULP_PLOGI_PRESERVE
:
988 job_code
= JOB_PORT_GETMAP_PLOGI_ALL
;
992 return (FC_INVALID_REQUEST
);
995 * Submit a job request to the job handler
996 * thread to get the map and wait
998 job
= fctl_alloc_job(job_code
, 0, NULL
, NULL
, KM_SLEEP
);
999 job
->job_private
= (opaque_t
)map
;
1000 job
->job_arg
= (opaque_t
)len
;
1001 fctl_enque_job(port
, job
);
1005 * The result of the last I/O operation is
1006 * in job_code. We don't care to look at it
1007 * Rather we look at the number of devices
1008 * that are found to fill out the map for
1011 fctl_dealloc_job(job
);
1015 * If we're here, we're returning a map to the caller, which means
1016 * we'd better make sure every pd in that map has the
1017 * PD_GIVEN_TO_ULPS flag set.
1023 while (tmp_len
-- != 0) {
1024 if (tmp_map
->map_state
!= PORT_DEVICE_INVALID
) {
1025 fc_remote_port_t
*pd
=
1026 (fc_remote_port_t
*)tmp_map
->map_pd
;
1027 mutex_enter(&pd
->pd_mutex
);
1028 pd
->pd_aux_flags
|= PD_GIVEN_TO_ULPS
;
1029 mutex_exit(&pd
->pd_mutex
);
1034 return (FC_SUCCESS
);
1039 fc_ulp_login(opaque_t port_handle
, fc_packet_t
**ulp_pkt
, uint32_t listlen
)
1041 int rval
= FC_SUCCESS
;
1044 fc_packet_t
**tmp_array
;
1046 fc_local_port_t
*port
= port_handle
;
1047 fc_ulp_rscn_info_t
*rscnp
=
1048 (fc_ulp_rscn_info_t
*)(ulp_pkt
[0])->pkt_ulp_rscn_infop
;
1051 * If the port is OFFLINE, or if the port driver is
1052 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1055 mutex_enter(&port
->fp_mutex
);
1056 if (port
->fp_statec_busy
) {
1057 mutex_exit(&port
->fp_mutex
);
1058 return (FC_STATEC_BUSY
);
1061 if ((FC_PORT_STATE_MASK(port
->fp_state
) == FC_STATE_OFFLINE
) ||
1062 (port
->fp_soft_state
&
1063 (FP_SOFT_IN_DETACH
| FP_SOFT_SUSPEND
| FP_SOFT_POWER_DOWN
))) {
1064 mutex_exit(&port
->fp_mutex
);
1065 return (FC_OFFLINE
);
1069 * If the rscn count in the packet is not the same as the rscn count
1070 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1072 if ((rscnp
!= NULL
) &&
1073 (rscnp
->ulp_rscn_count
!= FC_INVALID_RSCN_COUNT
) &&
1074 (rscnp
->ulp_rscn_count
!= port
->fp_rscn_count
)) {
1075 mutex_exit(&port
->fp_mutex
);
1076 return (FC_DEVICE_BUSY_NEW_RSCN
);
1079 mutex_exit(&port
->fp_mutex
);
1081 tmp_array
= kmem_zalloc(sizeof (*tmp_array
) * listlen
, KM_SLEEP
);
1082 for (count
= 0; count
< listlen
; count
++) {
1083 tmp_array
[count
] = ulp_pkt
[count
];
1086 job_flags
= ((ulp_pkt
[0]->pkt_tran_flags
) & FC_TRAN_NO_INTR
)
1087 ? 0 : JOB_TYPE_FCTL_ASYNC
;
1095 polled
= ((ulp_pkt
[0]->pkt_tran_flags
) &
1096 FC_TRAN_NO_INTR
) ? 0 : JOB_TYPE_FCTL_ASYNC
;
1098 for (count
= 0; count
< listlen
; count
++) {
1099 next
= ((ulp_pkt
[count
]->pkt_tran_flags
)
1100 & FC_TRAN_NO_INTR
) ? 0 : JOB_TYPE_FCTL_ASYNC
;
1101 ASSERT(next
== polled
);
1106 job
= fctl_alloc_job(JOB_PLOGI_GROUP
, job_flags
, NULL
, NULL
, KM_SLEEP
);
1107 job
->job_ulp_pkts
= tmp_array
;
1108 job
->job_ulp_listlen
= listlen
;
1113 pkt
= tmp_array
[listlen
];
1114 if (pkt
->pkt_pd
== NULL
) {
1115 pkt
->pkt_state
= FC_PKT_SUCCESS
;
1119 mutex_enter(&pkt
->pkt_pd
->pd_mutex
);
1120 if (pkt
->pkt_pd
->pd_flags
== PD_ELS_IN_PROGRESS
||
1121 pkt
->pkt_pd
->pd_flags
== PD_ELS_MARK
) {
1123 * Set the packet state and let the port
1124 * driver call the completion routine
1127 mutex_exit(&pkt
->pkt_pd
->pd_mutex
);
1128 pkt
->pkt_state
= FC_PKT_ELS_IN_PROGRESS
;
1132 if (pkt
->pkt_pd
->pd_state
== PORT_DEVICE_INVALID
||
1133 pkt
->pkt_pd
->pd_type
== PORT_DEVICE_OLD
) {
1134 mutex_exit(&pkt
->pkt_pd
->pd_mutex
);
1135 pkt
->pkt_state
= FC_PKT_LOCAL_RJT
;
1138 mutex_exit(&pkt
->pkt_pd
->pd_mutex
);
1139 pkt
->pkt_state
= FC_PKT_SUCCESS
;
1142 fctl_enque_job(port
, job
);
1144 if (!(job_flags
& JOB_TYPE_FCTL_ASYNC
)) {
1146 rval
= job
->job_result
;
1147 fctl_dealloc_job(job
);
1155 fc_ulp_get_remote_port(opaque_t port_handle
, la_wwn_t
*pwwn
, int *error
,
1158 fc_local_port_t
*port
;
1160 fc_remote_port_t
*pd
;
1163 pd
= fctl_get_remote_port_by_pwwn(port
, pwwn
);
1166 *error
= FC_SUCCESS
;
1168 * A ULP now knows about this pd, so mark it
1170 mutex_enter(&pd
->pd_mutex
);
1171 pd
->pd_aux_flags
|= PD_GIVEN_TO_ULPS
;
1172 mutex_exit(&pd
->pd_mutex
);
1176 mutex_enter(&port
->fp_mutex
);
1177 if (FC_IS_TOP_SWITCH(port
->fp_topology
) && create
) {
1179 fctl_ns_req_t
*ns_cmd
;
1181 mutex_exit(&port
->fp_mutex
);
1183 job
= fctl_alloc_job(JOB_NS_CMD
, 0, NULL
, NULL
, KM_SLEEP
);
1190 ns_cmd
= fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t
),
1191 sizeof (ns_resp_gid_pn_t
), sizeof (ns_resp_gid_pn_t
),
1194 if (ns_cmd
== NULL
) {
1195 fctl_dealloc_job(job
);
1199 ns_cmd
->ns_cmd_code
= NS_GID_PN
;
1200 ((ns_req_gid_pn_t
*)(ns_cmd
->ns_cmd_buf
))->pwwn
= *pwwn
;
1202 job
->job_result
= FC_SUCCESS
;
1203 job
->job_private
= (void *)ns_cmd
;
1204 job
->job_counter
= 1;
1205 fctl_enque_job(port
, job
);
1208 if (job
->job_result
!= FC_SUCCESS
) {
1209 *error
= job
->job_result
;
1210 fctl_free_ns_cmd(ns_cmd
);
1211 fctl_dealloc_job(job
);
1214 d_id
= ((ns_resp_gid_pn_t
*)ns_cmd
->ns_data_buf
)->pid
.port_id
;
1215 fctl_free_ns_cmd(ns_cmd
);
1217 ns_cmd
= fctl_alloc_ns_cmd(sizeof (ns_req_gan_t
),
1218 sizeof (ns_resp_gan_t
), 0, FCTL_NS_CREATE_DEVICE
,
1220 ASSERT(ns_cmd
!= NULL
);
1222 ns_cmd
->ns_gan_max
= 1;
1223 ns_cmd
->ns_cmd_code
= NS_GA_NXT
;
1224 ns_cmd
->ns_gan_sid
= FCTL_GAN_START_ID
;
1225 ((ns_req_gan_t
*)(ns_cmd
->ns_cmd_buf
))->pid
.port_id
= d_id
- 1;
1226 ((ns_req_gan_t
*)(ns_cmd
->ns_cmd_buf
))->pid
.priv_lilp_posit
= 0;
1228 job
->job_result
= FC_SUCCESS
;
1229 job
->job_private
= (void *)ns_cmd
;
1230 job
->job_counter
= 1;
1231 fctl_enque_job(port
, job
);
1234 fctl_free_ns_cmd(ns_cmd
);
1235 if (job
->job_result
!= FC_SUCCESS
) {
1236 *error
= job
->job_result
;
1237 fctl_dealloc_job(job
);
1240 fctl_dealloc_job(job
);
1243 * Check if the port device is created now.
1245 pd
= fctl_get_remote_port_by_pwwn(port
, pwwn
);
1248 *error
= FC_FAILURE
;
1250 *error
= FC_SUCCESS
;
1253 * A ULP now knows about this pd, so mark it
1255 mutex_enter(&pd
->pd_mutex
);
1256 pd
->pd_aux_flags
|= PD_GIVEN_TO_ULPS
;
1257 mutex_exit(&pd
->pd_mutex
);
1260 mutex_exit(&port
->fp_mutex
);
1261 *error
= FC_FAILURE
;
1269 * If a NS object exists in the host and query is performed
1270 * on that object, we should retrieve it from our basket
1271 * and return it right here, there by saving a request going
1272 * all the up to the Name Server.
1275 fc_ulp_port_ns(opaque_t port_handle
, opaque_t pd
, fc_ns_cmd_t
*ns_req
)
1280 fctl_ns_req_t
*ns_cmd
;
1281 fc_local_port_t
*port
= port_handle
;
1283 mutex_enter(&port
->fp_mutex
);
1284 fabric
= FC_IS_TOP_SWITCH(port
->fp_topology
) ? 1 : 0;
1285 mutex_exit(&port
->fp_mutex
);
1288 * Name server query can't be performed for devices not in Fabric
1290 if (!fabric
&& pd
) {
1291 return (FC_BADOBJECT
);
1294 if (FC_IS_CMD_A_REG(ns_req
->ns_cmd
)) {
1296 rval
= fctl_update_host_ns_values(port
, ns_req
);
1297 if (rval
!= FC_SUCCESS
) {
1302 * Guess what, FC-GS-2 currently prohibits (not
1303 * in the strongest language though) setting of
1304 * NS object values by other ports. But we might
1305 * get that changed to at least accommodate setting
1306 * symbolic node/port names - But if disks/tapes
1307 * were going to provide a method to set these
1308 * values directly (which in turn might register
1309 * with the NS when they come up; yep, for that
1310 * to happen the disks will have to be very well
1311 * behaved Fabric citizen) we won't need to
1312 * register the symbolic port/node names for
1313 * other ports too (rather send down SCSI commands
1314 * to the devices to set the names)
1316 * Be that as it may, let's continue to fail
1317 * registration requests for other ports. period.
1319 return (FC_BADOBJECT
);
1323 return (FC_SUCCESS
);
1325 } else if (!fabric
) {
1326 return (fctl_retrieve_host_ns_values(port
, ns_req
));
1329 job
= fctl_alloc_job(JOB_NS_CMD
, 0, NULL
, NULL
, KM_SLEEP
);
1330 ASSERT(job
!= NULL
);
1332 ns_cmd
= fctl_alloc_ns_cmd(ns_req
->ns_req_len
,
1333 ns_req
->ns_resp_len
, ns_req
->ns_resp_len
, 0, KM_SLEEP
);
1334 ASSERT(ns_cmd
!= NULL
);
1335 ns_cmd
->ns_cmd_code
= ns_req
->ns_cmd
;
1336 bcopy(ns_req
->ns_req_payload
, ns_cmd
->ns_cmd_buf
,
1337 ns_req
->ns_req_len
);
1339 job
->job_private
= (void *)ns_cmd
;
1340 fctl_enque_job(port
, job
);
1342 rval
= job
->job_result
;
1344 if (ns_req
->ns_resp_len
>= ns_cmd
->ns_data_len
) {
1345 bcopy(ns_cmd
->ns_data_buf
, ns_req
->ns_resp_payload
,
1346 ns_cmd
->ns_data_len
);
1348 bcopy(&ns_cmd
->ns_resp_hdr
, &ns_req
->ns_resp_hdr
,
1349 sizeof (fc_ct_header_t
));
1351 fctl_free_ns_cmd(ns_cmd
);
1352 fctl_dealloc_job(job
);
1359 fc_ulp_transport(opaque_t port_handle
, fc_packet_t
*pkt
)
1362 fc_local_port_t
*port
;
1363 fc_remote_port_t
*pd
, *newpd
;
1364 fc_ulp_rscn_info_t
*rscnp
=
1365 (fc_ulp_rscn_info_t
*)pkt
->pkt_ulp_rscn_infop
;
1369 if (pkt
->pkt_tran_flags
& FC_TRAN_DUMPING
) {
1370 return (port
->fp_fca_tran
->fca_transport(
1371 port
->fp_fca_handle
, pkt
));
1374 mutex_enter(&port
->fp_mutex
);
1375 if (port
->fp_statec_busy
) {
1376 mutex_exit(&port
->fp_mutex
);
1377 return (FC_STATEC_BUSY
);
1380 /* A locus of race conditions */
1381 if (((FC_PORT_STATE_MASK(port
->fp_state
)) == FC_STATE_OFFLINE
) ||
1382 (port
->fp_soft_state
&
1383 (FP_SOFT_IN_DETACH
| FP_SOFT_SUSPEND
| FP_SOFT_POWER_DOWN
))) {
1384 mutex_exit(&port
->fp_mutex
);
1385 return (FC_OFFLINE
);
1389 * If the rscn count in the packet is not the same as the rscn count
1390 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1392 if ((rscnp
!= NULL
) &&
1393 (rscnp
->ulp_rscn_count
!= FC_INVALID_RSCN_COUNT
) &&
1394 (rscnp
->ulp_rscn_count
!= port
->fp_rscn_count
)) {
1395 mutex_exit(&port
->fp_mutex
);
1396 return (FC_DEVICE_BUSY_NEW_RSCN
);
1401 if (pd
->pd_type
== PORT_DEVICE_OLD
||
1402 pd
->pd_state
== PORT_DEVICE_INVALID
) {
1404 newpd
= fctl_get_remote_port_by_pwwn_mutex_held(port
,
1408 * The remote port (pd) in the packet is no longer
1409 * usable, as the old pd still exists we can use the
1410 * WWN to check if we have a current pd for the device
1411 * we want. Either way we continue with the old logic
1412 * whether we have a new pd or not, as the new pd
1413 * could be bad, or have become unusable.
1415 if ((newpd
) && (newpd
!= pd
)) {
1418 * There is a better remote port (pd) to try,
1419 * so we need to fix the reference counts, etc.
1421 mutex_enter(&newpd
->pd_mutex
);
1422 newpd
->pd_ref_count
++;
1423 pkt
->pkt_pd
= newpd
;
1424 mutex_exit(&newpd
->pd_mutex
);
1426 mutex_enter(&pd
->pd_mutex
);
1428 if ((pd
->pd_state
== PORT_DEVICE_INVALID
) &&
1429 (pd
->pd_ref_count
== 0)) {
1430 fc_remote_node_t
*node
=
1431 pd
->pd_remote_nodep
;
1433 mutex_exit(&pd
->pd_mutex
);
1434 mutex_exit(&port
->fp_mutex
);
1437 * This will create another PD hole
1438 * where we have a reference to a pd,
1439 * but someone else could remove it.
1441 if ((fctl_destroy_remote_port(port
, pd
)
1442 == 0) && (node
!= NULL
)) {
1443 fctl_destroy_remote_node(node
);
1445 mutex_enter(&port
->fp_mutex
);
1447 mutex_exit(&pd
->pd_mutex
);
1453 if (pd
->pd_state
!= PORT_DEVICE_LOGGED_IN
) {
1454 rval
= (pd
->pd_state
== PORT_DEVICE_VALID
) ?
1455 FC_LOGINREQ
: FC_BADDEV
;
1456 mutex_exit(&port
->fp_mutex
);
1460 if (pd
->pd_flags
!= PD_IDLE
) {
1461 mutex_exit(&port
->fp_mutex
);
1462 return (FC_DEVICE_BUSY
);
1465 if (pd
->pd_type
== PORT_DEVICE_OLD
||
1466 pd
->pd_state
== PORT_DEVICE_INVALID
) {
1467 mutex_exit(&port
->fp_mutex
);
1471 } else if (FC_IS_REAL_DEVICE(pkt
->pkt_cmd_fhdr
.d_id
)) {
1472 mutex_exit(&port
->fp_mutex
);
1473 return (FC_BADPACKET
);
1475 mutex_exit(&port
->fp_mutex
);
1477 return (port
->fp_fca_tran
->fca_transport(port
->fp_fca_handle
, pkt
));
1482 fc_ulp_issue_els(opaque_t port_handle
, fc_packet_t
*pkt
)
1485 fc_local_port_t
*port
= port_handle
;
1486 fc_remote_port_t
*pd
;
1487 fc_ulp_rscn_info_t
*rscnp
=
1488 (fc_ulp_rscn_info_t
*)pkt
->pkt_ulp_rscn_infop
;
1491 * If the port is OFFLINE, or if the port driver is
1492 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1495 mutex_enter(&port
->fp_mutex
);
1496 if ((FC_PORT_STATE_MASK(port
->fp_state
) == FC_STATE_OFFLINE
) ||
1497 (port
->fp_soft_state
&
1498 (FP_SOFT_IN_DETACH
| FP_SOFT_SUSPEND
| FP_SOFT_POWER_DOWN
))) {
1499 mutex_exit(&port
->fp_mutex
);
1500 return (FC_OFFLINE
);
1503 if (port
->fp_statec_busy
) {
1504 mutex_exit(&port
->fp_mutex
);
1505 return (FC_STATEC_BUSY
);
1509 * If the rscn count in the packet is not the same as the rscn count
1510 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1512 if ((rscnp
!= NULL
) &&
1513 (rscnp
->ulp_rscn_count
!= FC_INVALID_RSCN_COUNT
) &&
1514 (rscnp
->ulp_rscn_count
!= port
->fp_rscn_count
)) {
1515 mutex_exit(&port
->fp_mutex
);
1516 return (FC_DEVICE_BUSY_NEW_RSCN
);
1519 mutex_exit(&port
->fp_mutex
);
1521 if ((pd
= pkt
->pkt_pd
) != NULL
) {
1522 mutex_enter(&pd
->pd_mutex
);
1523 if (pd
->pd_state
!= PORT_DEVICE_LOGGED_IN
) {
1524 rval
= (pd
->pd_state
== PORT_DEVICE_VALID
) ?
1525 FC_LOGINREQ
: FC_BADDEV
;
1526 mutex_exit(&pd
->pd_mutex
);
1530 if (pd
->pd_flags
!= PD_IDLE
) {
1531 mutex_exit(&pd
->pd_mutex
);
1532 return (FC_DEVICE_BUSY
);
1534 if (pd
->pd_type
== PORT_DEVICE_OLD
||
1535 pd
->pd_state
== PORT_DEVICE_INVALID
) {
1536 mutex_exit(&pd
->pd_mutex
);
1539 mutex_exit(&pd
->pd_mutex
);
1542 return (port
->fp_fca_tran
->fca_els_send(port
->fp_fca_handle
, pkt
));
1547 fc_ulp_uballoc(opaque_t port_handle
, uint32_t *count
, uint32_t size
,
1548 uint32_t type
, uint64_t *tokens
)
1550 fc_local_port_t
*port
= port_handle
;
1552 return (port
->fp_fca_tran
->fca_ub_alloc(port
->fp_fca_handle
,
1553 tokens
, size
, count
, type
));
1558 fc_ulp_ubfree(opaque_t port_handle
, uint32_t count
, uint64_t *tokens
)
1560 fc_local_port_t
*port
= port_handle
;
1562 return (port
->fp_fca_tran
->fca_ub_free(port
->fp_fca_handle
,
1568 fc_ulp_ubrelease(opaque_t port_handle
, uint32_t count
, uint64_t *tokens
)
1570 fc_local_port_t
*port
= port_handle
;
1572 return (port
->fp_fca_tran
->fca_ub_release(port
->fp_fca_handle
,
1578 fc_ulp_abort(opaque_t port_handle
, fc_packet_t
*pkt
, int flags
)
1580 fc_local_port_t
*port
= port_handle
;
1582 return (port
->fp_fca_tran
->fca_abort(port
->fp_fca_handle
, pkt
, flags
));
1587 * Submit an asynchronous request to the job handler if the sleep
1588 * flag is set to KM_NOSLEEP, as such calls could have been made
1589 * in interrupt contexts, and the goal is to avoid busy waiting,
1590 * blocking on a conditional variable, a semaphore or any of the
1591 * synchronization primitives. A noticeable draw back with this
1592 * asynchronous request is that an FC_SUCCESS is returned long
1593 * before the reset is complete (successful or not).
1596 fc_ulp_linkreset(opaque_t port_handle
, la_wwn_t
*pwwn
, int sleep
)
1599 fc_local_port_t
*port
;
1604 * Many a times, this function is called from interrupt
1605 * contexts and there have been several dead locks and
1606 * hangs - One of the simplest work arounds is to fib
1607 * if a RESET is in progress.
1609 mutex_enter(&port
->fp_mutex
);
1610 if (port
->fp_soft_state
& FP_SOFT_IN_LINK_RESET
) {
1611 mutex_exit(&port
->fp_mutex
);
1612 return (FC_SUCCESS
);
1616 * Ward off this reset if a state change is in progress.
1618 if (port
->fp_statec_busy
) {
1619 mutex_exit(&port
->fp_mutex
);
1620 return (FC_STATEC_BUSY
);
1622 port
->fp_soft_state
|= FP_SOFT_IN_LINK_RESET
;
1623 mutex_exit(&port
->fp_mutex
);
1625 if (fctl_busy_port(port
) != 0) {
1626 mutex_enter(&port
->fp_mutex
);
1627 port
->fp_soft_state
&= ~FP_SOFT_IN_LINK_RESET
;
1628 mutex_exit(&port
->fp_mutex
);
1629 return (FC_FAILURE
);
1632 if (sleep
== KM_SLEEP
) {
1633 job
= fctl_alloc_job(JOB_LINK_RESET
, 0, NULL
, NULL
, sleep
);
1634 ASSERT(job
!= NULL
);
1636 job
->job_private
= (void *)pwwn
;
1637 job
->job_counter
= 1;
1638 fctl_enque_job(port
, job
);
1641 mutex_enter(&port
->fp_mutex
);
1642 port
->fp_soft_state
&= ~FP_SOFT_IN_LINK_RESET
;
1643 mutex_exit(&port
->fp_mutex
);
1645 fctl_idle_port(port
);
1647 rval
= job
->job_result
;
1648 fctl_dealloc_job(job
);
1650 job
= fctl_alloc_job(JOB_LINK_RESET
, JOB_TYPE_FCTL_ASYNC
,
1651 fctl_link_reset_done
, port
, sleep
);
1653 mutex_enter(&port
->fp_mutex
);
1654 port
->fp_soft_state
&= ~FP_SOFT_IN_LINK_RESET
;
1655 mutex_exit(&port
->fp_mutex
);
1656 fctl_idle_port(port
);
1659 job
->job_private
= (void *)pwwn
;
1660 job
->job_counter
= 1;
1661 fctl_priority_enque_job(port
, job
);
1670 fc_ulp_port_reset(opaque_t port_handle
, uint32_t cmd
)
1672 int rval
= FC_SUCCESS
;
1673 fc_local_port_t
*port
= port_handle
;
1677 rval
= port
->fp_fca_tran
->fca_reset(
1678 port
->fp_fca_handle
, FC_FCA_LINK_RESET
);
1681 case FC_RESET_ADAPTER
:
1682 rval
= port
->fp_fca_tran
->fca_reset(
1683 port
->fp_fca_handle
, FC_FCA_RESET
);
1687 rval
= port
->fp_fca_tran
->fca_reset(
1688 port
->fp_fca_handle
, FC_FCA_CORE
);
1691 case FC_RESET_CRASH
:
1692 rval
= port
->fp_fca_tran
->fca_reset(
1693 port
->fp_fca_handle
, FC_FCA_RESET_CORE
);
1705 fc_ulp_get_port_login_params(opaque_t port_handle
, la_els_logi_t
*login_params
)
1707 fc_local_port_t
*port
= port_handle
;
1709 /* Copy the login parameters */
1710 *login_params
= port
->fp_service_params
;
1711 return (FC_SUCCESS
);
1716 fc_ulp_get_port_instance(opaque_t port_handle
)
1718 fc_local_port_t
*port
= port_handle
;
1720 return (port
->fp_instance
);
1725 fc_ulp_get_port_handle(int port_instance
)
1727 opaque_t port_handle
= NULL
;
1730 mutex_enter(&fctl_port_lock
);
1731 for (cur
= fctl_fca_portlist
; cur
; cur
= cur
->port_next
) {
1732 if (cur
->port_handle
->fp_instance
== port_instance
) {
1733 port_handle
= (opaque_t
)cur
->port_handle
;
1737 mutex_exit(&fctl_port_lock
);
1739 return (port_handle
);
1744 fc_ulp_error(int fc_errno
, char **errmsg
)
1746 return (fctl_error(fc_errno
, errmsg
));
1751 fc_ulp_pkt_error(fc_packet_t
*pkt
, char **state
, char **reason
,
1752 char **action
, char **expln
)
1754 return (fctl_pkt_error(pkt
, state
, reason
, action
, expln
));
1759 * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
1762 fc_ulp_is_name_present(caddr_t ulp_name
)
1764 int rval
= FC_FAILURE
;
1765 fc_ulp_list_t
*list
;
1767 mutex_enter(&fctl_ulp_list_mutex
);
1768 for (list
= fctl_ulp_list
; list
!= NULL
; list
= list
->ulp_next
) {
1769 if (strcmp(list
->ulp_info
->ulp_name
, ulp_name
) == 0) {
1774 mutex_exit(&fctl_ulp_list_mutex
);
1781 * Return port WWN for a port Identifier
1784 fc_ulp_get_pwwn_by_did(opaque_t port_handle
, fc_portid_t d_id
, la_wwn_t
*pwwn
)
1786 int rval
= FC_FAILURE
;
1787 fc_remote_port_t
*pd
;
1788 fc_local_port_t
*port
= port_handle
;
1790 pd
= fctl_get_remote_port_by_did(port
, d_id
.port_id
);
1792 mutex_enter(&pd
->pd_mutex
);
1793 *pwwn
= pd
->pd_port_name
;
1794 mutex_exit(&pd
->pd_mutex
);
1803 * Return a port map for a port WWN
1806 fc_ulp_pwwn_to_portmap(opaque_t port_handle
, la_wwn_t
*bytes
, fc_portmap_t
*map
)
1808 fc_local_port_t
*port
= port_handle
;
1809 fc_remote_node_t
*node
;
1810 fc_remote_port_t
*pd
;
1812 pd
= fctl_get_remote_port_by_pwwn(port
, bytes
);
1814 return (FC_FAILURE
);
1817 mutex_enter(&pd
->pd_mutex
);
1818 map
->map_pwwn
= pd
->pd_port_name
;
1819 map
->map_did
= pd
->pd_port_id
;
1820 map
->map_hard_addr
= pd
->pd_hard_addr
;
1821 map
->map_state
= pd
->pd_state
;
1822 map
->map_type
= pd
->pd_type
;
1825 ASSERT(map
->map_type
<= PORT_DEVICE_DELETE
);
1827 bcopy(pd
->pd_fc4types
, map
->map_fc4_types
, sizeof (pd
->pd_fc4types
));
1829 node
= pd
->pd_remote_nodep
;
1830 mutex_exit(&pd
->pd_mutex
);
1833 mutex_enter(&node
->fd_mutex
);
1834 map
->map_nwwn
= node
->fd_node_name
;
1835 mutex_exit(&node
->fd_mutex
);
1839 return (FC_SUCCESS
);
1844 fc_ulp_get_fca_device(opaque_t port_handle
, fc_portid_t d_id
)
1846 fc_local_port_t
*port
= port_handle
;
1848 if (port
->fp_fca_tran
->fca_get_device
== NULL
) {
1852 return (port
->fp_fca_tran
->fca_get_device(port
->fp_fca_handle
, d_id
));
1857 fc_ulp_port_notify(opaque_t port_handle
, uint32_t cmd
)
1859 int rval
= FC_SUCCESS
;
1860 fc_local_port_t
*port
= port_handle
;
1862 if (port
->fp_fca_tran
->fca_notify
) {
1863 mutex_enter(&port
->fp_mutex
);
1865 case FC_NOTIFY_TARGET_MODE
:
1866 port
->fp_options
|= FP_TARGET_MODE
;
1868 case FC_NOTIFY_NO_TARGET_MODE
:
1869 port
->fp_options
&= ~FP_TARGET_MODE
;
1872 mutex_exit(&port
->fp_mutex
);
1873 rval
= port
->fp_fca_tran
->fca_notify(port
->fp_fca_handle
, cmd
);
1881 fc_ulp_disable_relogin(opaque_t
*fc_port
, la_wwn_t
*pwwn
)
1883 fc_remote_port_t
*pd
=
1884 fctl_get_remote_port_by_pwwn((fc_local_port_t
*)fc_port
, pwwn
);
1887 mutex_enter(&pd
->pd_mutex
);
1888 pd
->pd_aux_flags
|= PD_DISABLE_RELOGIN
;
1889 mutex_exit(&pd
->pd_mutex
);
1895 fc_ulp_enable_relogin(opaque_t
*fc_port
, la_wwn_t
*pwwn
)
1897 fc_remote_port_t
*pd
=
1898 fctl_get_remote_port_by_pwwn((fc_local_port_t
*)fc_port
, pwwn
);
1901 mutex_enter(&pd
->pd_mutex
);
1902 pd
->pd_aux_flags
&= ~PD_DISABLE_RELOGIN
;
1903 mutex_exit(&pd
->pd_mutex
);
1910 * Overload the FCA bus_ops vector in its dev_ops with
1911 * fctl_fca_busops to handle all the INITchilds for "sf"
1912 * in one common place.
1914 * Should be called from FCA _init routine.
1917 fc_fca_init(struct dev_ops
*fca_devops_p
)
1920 fca_devops_p
->devo_bus_ops
= &fctl_fca_busops
;
1921 #endif /* __lock_lint */
1929 fc_fca_attach(dev_info_t
*fca_dip
, fc_fca_tran_t
*tran
)
1932 * When we are in a position to offer downward compatibility
1933 * we should change the following check to allow lower revision
1934 * of FCAs; But we aren't there right now.
1936 if (tran
->fca_version
!= FCTL_FCA_MODREV_5
) {
1937 const char *name
= ddi_driver_name(fca_dip
);
1939 ASSERT(name
!= NULL
);
1941 cmn_err(CE_WARN
, "fctl: FCA %s version mismatch"
1942 " please upgrade %s", name
, name
);
1943 return (DDI_FAILURE
);
1946 ddi_set_driver_private(fca_dip
, (caddr_t
)tran
);
1947 return (DDI_SUCCESS
);
1955 fc_fca_detach(dev_info_t
*fca_dip
)
1957 ddi_set_driver_private(fca_dip
, NULL
);
1958 return (DDI_SUCCESS
);
1963 * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
1964 * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
1965 * Link Service responses such as BA_RJT and Extended Link Service response
1966 * such as LS_RJT. If the response is a Link_Data Frame or something that
1967 * this function doesn't understand return FC_FAILURE; Otherwise, fill out
1968 * various fields (state, action, reason, expln) from the response gotten
1969 * in the packet and return FC_SUCCESS.
1972 fc_fca_update_errors(fc_packet_t
*pkt
)
1974 int ret
= FC_SUCCESS
;
1976 switch (pkt
->pkt_resp_fhdr
.r_ctl
) {
1980 prjt
= pkt
->pkt_resp_fhdr
.ro
;
1981 pkt
->pkt_state
= FC_PKT_NPORT_RJT
;
1982 pkt
->pkt_action
= (prjt
& 0xFF000000) >> 24;
1983 pkt
->pkt_reason
= (prjt
& 0xFF0000) >> 16;
1990 frjt
= pkt
->pkt_resp_fhdr
.ro
;
1991 pkt
->pkt_state
= FC_PKT_FABRIC_RJT
;
1992 pkt
->pkt_action
= (frjt
& 0xFF000000) >> 24;
1993 pkt
->pkt_reason
= (frjt
& 0xFF0000) >> 16;
2000 pbsy
= pkt
->pkt_resp_fhdr
.ro
;
2001 pkt
->pkt_state
= FC_PKT_NPORT_BSY
;
2002 pkt
->pkt_action
= (pbsy
& 0xFF000000) >> 24;
2003 pkt
->pkt_reason
= (pbsy
& 0xFF0000) >> 16;
2007 case R_CTL_F_BSY_LC
:
2008 case R_CTL_F_BSY_DF
: {
2011 fbsy
= pkt
->pkt_resp_fhdr
.type
;
2012 pkt
->pkt_state
= FC_PKT_FABRIC_BSY
;
2013 pkt
->pkt_reason
= (fbsy
& 0xF0) >> 4;
2017 case R_CTL_LS_BA_RJT
: {
2020 brjt
= *(uint32_t *)pkt
->pkt_resp
;
2021 pkt
->pkt_state
= FC_PKT_BA_RJT
;
2022 pkt
->pkt_reason
= (brjt
& 0xFF0000) >> 16;
2023 pkt
->pkt_expln
= (brjt
& 0xFF00) >> 8;
2027 case R_CTL_ELS_RSP
: {
2028 la_els_rjt_t
*lsrjt
;
2030 lsrjt
= (la_els_rjt_t
*)pkt
->pkt_resp
;
2031 if (lsrjt
->ls_code
.ls_code
== LA_ELS_RJT
) {
2032 pkt
->pkt_state
= FC_PKT_LS_RJT
;
2033 pkt
->pkt_reason
= lsrjt
->reason
;
2034 pkt
->pkt_action
= lsrjt
->action
;
2050 fc_fca_error(int fc_errno
, char **errmsg
)
2052 return (fctl_error(fc_errno
, errmsg
));
2057 fc_fca_pkt_error(fc_packet_t
*pkt
, char **state
, char **reason
,
2058 char **action
, char **expln
)
2060 return (fctl_pkt_error(pkt
, state
, reason
, action
, expln
));
2065 * WWN to string goodie. Unpredictable results will happen
2066 * if enough memory isn't supplied in str argument. If you
2067 * are wondering how much does this routine need, it is just
2068 * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
2069 * argument should have atleast 17 bytes allocated.
2072 fc_wwn_to_str(la_wwn_t
*wwn
, caddr_t str
)
2076 for (count
= 0; count
< FCTL_WWN_SIZE(wwn
); count
++, str
+= 2) {
2077 (void) sprintf(str
, "%02x", wwn
->raw_wwn
[count
]);
2082 #define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : \
2083 ((x) >= 'a' && (x) <= 'f') ? \
2084 ((x) - 'a' + 10) : ((x) - 'A' + 10))
2087 fc_str_to_wwn(caddr_t str
, la_wwn_t
*wwn
)
2093 byte
= FC_ATOB(*str
);
2095 byte
= byte
<< 4 | FC_ATOB(*str
);
2097 wwn
->raw_wwn
[count
++] = byte
;
2102 * FCA driver's intercepted bus control operations.
2105 fctl_fca_bus_ctl(dev_info_t
*fca_dip
, dev_info_t
*rip
,
2106 ddi_ctl_enum_t op
, void *arg
, void *result
)
2109 case DDI_CTLOPS_REPORTDEV
:
2112 case DDI_CTLOPS_IOMIN
:
2115 case DDI_CTLOPS_INITCHILD
:
2116 return (fctl_initchild(fca_dip
, (dev_info_t
*)arg
));
2118 case DDI_CTLOPS_UNINITCHILD
:
2119 return (fctl_uninitchild(fca_dip
, (dev_info_t
*)arg
));
2122 return (ddi_ctlops(fca_dip
, rip
, op
, arg
, result
));
2125 return (DDI_SUCCESS
);
2130 * FCAs indicate the maximum number of ports supported in their
2131 * tran structure. Fail the INITCHILD if the child port number
2132 * is any greater than the maximum number of ports supported
2136 fctl_initchild(dev_info_t
*fca_dip
, dev_info_t
*port_dip
)
2142 fc_fca_tran_t
*tran
;
2146 port_len
= sizeof (port_no
);
2148 /* physical port do not has this property */
2149 portprop
= ddi_prop_get_int(DDI_DEV_T_ANY
, port_dip
,
2150 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
2151 "phyport-instance", -1);
2153 if ((portprop
== -1) && ndi_dev_is_persistent_node(port_dip
)) {
2155 * Clear any addr bindings created by fcode interpreter
2156 * in devi_last_addr so that a ndi_devi_find should never
2157 * return this fcode node.
2159 ddi_set_name_addr(port_dip
, NULL
);
2160 return (DDI_FAILURE
);
2163 rval
= ddi_prop_op(DDI_DEV_T_ANY
, port_dip
, PROP_LEN_AND_VAL_BUF
,
2164 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
, "port",
2165 (caddr_t
)&port_no
, &port_len
);
2167 if (rval
!= DDI_SUCCESS
) {
2168 return (DDI_FAILURE
);
2171 tran
= (fc_fca_tran_t
*)ddi_get_driver_private(fca_dip
);
2172 ASSERT(tran
!= NULL
);
2174 (void) sprintf((char *)name
, "%x,0", port_no
);
2175 ddi_set_name_addr(port_dip
, name
);
2177 dip
= ndi_devi_find(fca_dip
, ddi_binding_name(port_dip
), name
);
2180 * Even though we never initialize FCode nodes of fp, such a node
2181 * could still be there after a DR operation. There will only be
2182 * one FCode node, so if this is the one, clear it and issue a
2183 * ndi_devi_find again.
2185 if ((portprop
== -1) && dip
&& ndi_dev_is_persistent_node(dip
)) {
2186 ddi_set_name_addr(dip
, NULL
);
2187 dip
= ndi_devi_find(fca_dip
, ddi_binding_name(port_dip
), name
);
2190 if ((portprop
== -1) && dip
&& (dip
!= port_dip
)) {
2192 * Here we have a duplicate .conf entry. Clear the addr
2193 * set previously and return failure.
2195 ddi_set_name_addr(port_dip
, NULL
);
2196 return (DDI_FAILURE
);
2199 return (DDI_SUCCESS
);
2205 fctl_uninitchild(dev_info_t
*fca_dip
, dev_info_t
*port_dip
)
2207 ddi_set_name_addr(port_dip
, NULL
);
2208 return (DDI_SUCCESS
);
2213 fctl_findchild(dev_info_t
*pdip
, char *cname
, char *caddr
)
2218 ASSERT(cname
!= NULL
&& caddr
!= NULL
);
2219 /* ASSERT(DEVI_BUSY_OWNED(pdip)); */
2221 for (dip
= ddi_get_child(pdip
); dip
!= NULL
;
2222 dip
= ddi_get_next_sibling(dip
)) {
2223 if (strcmp(cname
, ddi_node_name(dip
)) != 0) {
2227 if ((addr
= ddi_get_name_addr(dip
)) == NULL
) {
2228 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, dip
,
2229 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
2230 "bus-addr", &addr
) == DDI_PROP_SUCCESS
) {
2231 if (strcmp(caddr
, addr
) == 0) {
2232 ddi_prop_free(addr
);
2235 ddi_prop_free(addr
);
2238 if (strcmp(caddr
, addr
) == 0) {
2248 fctl_check_npiv_portindex(dev_info_t
*dip
, int vindex
)
2251 fc_local_port_t
*port
;
2253 instance
= ddi_get_instance(dip
);
2254 port
= (fc_local_port_t
*)fc_ulp_get_port_handle(instance
);
2255 if ((!port
) || (vindex
<= 0) || (vindex
>= FC_NPIV_MAX_PORT
)) {
2260 mutex_enter(&port
->fp_mutex
);
2261 if (port
->fp_npiv_portindex
[i
] == 0) {
2262 mutex_exit(&port
->fp_mutex
);
2265 mutex_exit(&port
->fp_mutex
);
2270 fctl_get_npiv_portindex(dev_info_t
*dip
)
2273 fc_local_port_t
*port
;
2275 instance
= ddi_get_instance(dip
);
2276 port
= (fc_local_port_t
*)fc_ulp_get_port_handle(instance
);
2281 mutex_enter(&port
->fp_mutex
);
2282 for (i
= 0; i
< FC_NPIV_MAX_PORT
; i
++) {
2283 if (port
->fp_npiv_portindex
[i
] == 0) {
2284 mutex_exit(&port
->fp_mutex
);
2288 mutex_exit(&port
->fp_mutex
);
2294 fctl_set_npiv_portindex(dev_info_t
*dip
, int index
)
2297 fc_local_port_t
*port
;
2299 instance
= ddi_get_instance(dip
);
2300 port
= (fc_local_port_t
*)fc_ulp_get_port_handle(instance
);
2304 mutex_enter(&port
->fp_mutex
);
2305 port
->fp_npiv_portindex
[index
- 1] = 1;
2306 mutex_exit(&port
->fp_mutex
);
2311 fctl_fca_create_npivport(dev_info_t
*parent
,
2312 dev_info_t
*phydip
, char *nname
, char *pname
, uint32_t *vindex
)
2314 int rval
= 0, devstrlen
;
2315 char *devname
, *cname
, *caddr
, *devstr
;
2316 dev_info_t
*child
= NULL
;
2320 portnum
= fctl_get_npiv_portindex(phydip
);
2323 portnum
= fctl_check_npiv_portindex(phydip
, *vindex
);
2328 "Cann't find valid port index, fail to create devnode");
2329 return (NDI_FAILURE
);
2332 devname
= kmem_zalloc(MAXNAMELEN
, KM_SLEEP
);
2333 (void) sprintf(devname
, "fp@%x,0", portnum
);
2334 devstrlen
= strlen(devname
) + 1;
2335 devstr
= i_ddi_strdup(devname
, KM_SLEEP
);
2336 i_ddi_parse_name(devstr
, &cname
, &caddr
, NULL
);
2338 if (fctl_findchild(parent
, cname
, caddr
) != NULL
) {
2343 ndi_devi_alloc_sleep(parent
, cname
, DEVI_PSEUDO_NODEID
, &child
);
2344 if (child
== NULL
) {
2346 "fctl_create_npiv_port fail to create new devinfo");
2351 if (ndi_prop_update_string(DDI_DEV_T_NONE
, child
,
2352 "bus-addr", caddr
) != DDI_PROP_SUCCESS
) {
2353 cmn_err(CE_WARN
, "fctl%d: prop update bus-addr %s@%s failed",
2354 ddi_get_instance(parent
), cname
, caddr
);
2355 (void) ndi_devi_free(child
);
2360 if (strlen(nname
) != 0) {
2361 if (ndi_prop_update_string(DDI_DEV_T_NONE
, child
,
2362 "node-name", nname
) != DDI_PROP_SUCCESS
) {
2363 (void) ndi_devi_free(child
);
2369 if (strlen(pname
) != 0) {
2370 if (ndi_prop_update_string(DDI_DEV_T_NONE
, child
,
2371 "port-name", pname
) != DDI_PROP_SUCCESS
) {
2372 (void) ndi_devi_free(child
);
2378 if (ddi_prop_update_int(DDI_DEV_T_NONE
, child
,
2379 "port", portnum
) != DDI_PROP_SUCCESS
) {
2380 cmn_err(CE_WARN
, "fp%d: prop_update port %s@%s failed",
2381 ddi_get_instance(parent
), cname
, caddr
);
2382 (void) ndi_devi_free(child
);
2387 if (ddi_prop_update_int(DDI_DEV_T_NONE
, child
,
2388 "phyport-instance", ddi_get_instance(phydip
)) != DDI_PROP_SUCCESS
) {
2390 "fp%d: prop_update phyport-instance %s@%s failed",
2391 ddi_get_instance(parent
), cname
, caddr
);
2392 (void) ndi_devi_free(child
);
2397 rval
= ndi_devi_online(child
, NDI_ONLINE_ATTACH
);
2398 if (rval
!= NDI_SUCCESS
) {
2399 cmn_err(CE_WARN
, "fp%d: online_driver %s failed",
2400 ddi_get_instance(parent
), cname
);
2405 fctl_set_npiv_portindex(phydip
, portnum
);
2407 kmem_free(devstr
, devstrlen
);
2408 kmem_free(devname
, MAXNAMELEN
);
2415 fctl_add_port(fc_local_port_t
*port
)
2419 new = kmem_zalloc(sizeof (*new), KM_SLEEP
);
2421 mutex_enter(&fctl_port_lock
);
2422 new->port_handle
= port
;
2423 new->port_next
= fctl_fca_portlist
;
2424 fctl_fca_portlist
= new;
2425 mutex_exit(&fctl_port_lock
);
2430 fctl_remove_port(fc_local_port_t
*port
)
2432 fc_ulp_module_t
*mod
;
2433 fc_fca_port_t
*prev
;
2434 fc_fca_port_t
*list
;
2435 fc_ulp_ports_t
*ulp_port
;
2437 rw_enter(&fctl_ulp_lock
, RW_WRITER
);
2438 rw_enter(&fctl_mod_ports_lock
, RW_WRITER
);
2440 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
2441 ulp_port
= fctl_get_ulp_port(mod
, port
);
2442 if (ulp_port
== NULL
) {
2447 ASSERT((ulp_port
->port_dstate
& ULP_PORT_ATTACH
) == 0);
2448 #endif /* __lock_lint */
2450 (void) fctl_remove_ulp_port(mod
, port
);
2453 rw_exit(&fctl_mod_ports_lock
);
2454 rw_exit(&fctl_ulp_lock
);
2456 mutex_enter(&fctl_port_lock
);
2458 list
= fctl_fca_portlist
;
2460 while (list
!= NULL
) {
2461 if (list
->port_handle
== port
) {
2463 fctl_fca_portlist
= list
->port_next
;
2465 prev
->port_next
= list
->port_next
;
2467 kmem_free(list
, sizeof (*list
));
2471 list
= list
->port_next
;
2473 mutex_exit(&fctl_port_lock
);
2478 fctl_attach_ulps(fc_local_port_t
*port
, fc_attach_cmd_t cmd
,
2479 struct modlinkage
*linkage
)
2484 fc_ulp_module_t
*mod
;
2485 fc_ulp_port_info_t info
;
2486 fc_ulp_ports_t
*ulp_port
;
2488 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
2490 info
.port_linkage
= linkage
;
2491 info
.port_dip
= port
->fp_port_dip
;
2492 info
.port_handle
= (opaque_t
)port
;
2493 info
.port_dma_behavior
= port
->fp_dma_behavior
;
2494 info
.port_fcp_dma
= port
->fp_fcp_dma
;
2495 info
.port_acc_attr
= port
->fp_fca_tran
->fca_acc_attr
;
2496 info
.port_fca_pkt_size
= port
->fp_fca_tran
->fca_pkt_size
;
2497 info
.port_reset_action
= port
->fp_reset_action
;
2499 mutex_enter(&port
->fp_mutex
);
2502 * It is still possible that another thread could have gotten
2503 * into the detach process before we got here.
2505 if (port
->fp_soft_state
& FP_SOFT_IN_DETACH
) {
2506 mutex_exit(&port
->fp_mutex
);
2510 s_id
= port
->fp_port_id
.port_id
;
2511 if (port
->fp_statec_busy
) {
2512 info
.port_state
= port
->fp_bind_state
;
2514 info
.port_state
= port
->fp_state
;
2517 switch (state
= FC_PORT_STATE_MASK(info
.port_state
)) {
2519 case FC_STATE_NAMESERVICE
:
2520 info
.port_state
&= ~state
;
2521 info
.port_state
|= FC_STATE_ONLINE
;
2527 ASSERT((info
.port_state
& FC_STATE_LOOP
) == 0);
2529 info
.port_flags
= port
->fp_topology
;
2530 info
.port_pwwn
= port
->fp_service_params
.nport_ww_name
;
2531 info
.port_nwwn
= port
->fp_service_params
.node_ww_name
;
2532 mutex_exit(&port
->fp_mutex
);
2534 rw_enter(&fctl_ulp_lock
, RW_READER
);
2535 rw_enter(&fctl_mod_ports_lock
, RW_WRITER
);
2537 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
2538 if ((port
->fp_soft_state
& FP_SOFT_FCA_IS_NODMA
) &&
2539 (mod
->mod_info
->ulp_type
== FC_TYPE_IS8802_SNAP
)) {
2541 * We don't support IP over FC on FCOE HBA
2546 if ((ulp_port
= fctl_get_ulp_port(mod
, port
)) == NULL
) {
2547 ulp_port
= fctl_add_ulp_port(mod
, port
, KM_SLEEP
);
2548 ASSERT(ulp_port
!= NULL
);
2550 mutex_enter(&ulp_port
->port_mutex
);
2551 ulp_port
->port_statec
= ((info
.port_state
&
2552 FC_STATE_ONLINE
) ? FC_ULP_STATEC_ONLINE
:
2553 FC_ULP_STATEC_OFFLINE
);
2554 mutex_exit(&ulp_port
->port_mutex
);
2558 rw_downgrade(&fctl_mod_ports_lock
);
2560 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
2561 if ((port
->fp_soft_state
& FP_SOFT_FCA_IS_NODMA
) &&
2562 (mod
->mod_info
->ulp_type
== FC_TYPE_IS8802_SNAP
)) {
2564 * We don't support IP over FC on FCOE HBA
2569 ulp_port
= fctl_get_ulp_port(mod
, port
);
2570 ASSERT(ulp_port
!= NULL
);
2572 if (fctl_pre_attach(ulp_port
, cmd
) == FC_FAILURE
) {
2576 fctl_init_dma_attr(port
, mod
, &info
);
2578 rval
= mod
->mod_info
->ulp_port_attach(
2579 mod
->mod_info
->ulp_handle
, &info
, cmd
, s_id
);
2581 fctl_post_attach(mod
, ulp_port
, cmd
, rval
);
2583 if (rval
== FC_SUCCESS
&& cmd
== FC_CMD_ATTACH
&&
2584 strcmp(mod
->mod_info
->ulp_name
, "fcp") == 0) {
2585 ASSERT(ddi_get_driver_private(info
.port_dip
) != NULL
);
2589 rw_exit(&fctl_mod_ports_lock
);
2590 rw_exit(&fctl_ulp_lock
);
2595 fctl_pre_attach(fc_ulp_ports_t
*ulp_port
, fc_attach_cmd_t cmd
)
2597 int rval
= FC_SUCCESS
;
2599 mutex_enter(&ulp_port
->port_mutex
);
2603 if (ulp_port
->port_dstate
& ULP_PORT_ATTACH
) {
2609 ASSERT((ulp_port
->port_dstate
& ULP_PORT_POWER_DOWN
) == 0);
2610 if (!(ulp_port
->port_dstate
& ULP_PORT_ATTACH
) ||
2611 !(ulp_port
->port_dstate
& ULP_PORT_SUSPEND
)) {
2616 case FC_CMD_POWER_UP
:
2617 if (!(ulp_port
->port_dstate
& ULP_PORT_ATTACH
) ||
2618 !(ulp_port
->port_dstate
& ULP_PORT_POWER_DOWN
)) {
2624 if (rval
== FC_SUCCESS
) {
2625 ulp_port
->port_dstate
|= ULP_PORT_BUSY
;
2627 mutex_exit(&ulp_port
->port_mutex
);
2634 fctl_post_attach(fc_ulp_module_t
*mod
, fc_ulp_ports_t
*ulp_port
,
2635 fc_attach_cmd_t cmd
, int rval
)
2639 ASSERT(cmd
== FC_CMD_ATTACH
|| cmd
== FC_CMD_RESUME
||
2640 cmd
== FC_CMD_POWER_UP
);
2642 mutex_enter(&ulp_port
->port_mutex
);
2643 ulp_port
->port_dstate
&= ~ULP_PORT_BUSY
;
2645 be_chatty
= (rval
== FC_FAILURE_SILENT
) ? 0 : 1;
2647 if (rval
!= FC_SUCCESS
) {
2649 fc_local_port_t
*port
= ulp_port
->port_handle
;
2651 mutex_exit(&ulp_port
->port_mutex
);
2662 case FC_CMD_POWER_UP
:
2668 cmn_err(CE_WARN
, "!fctl(%d): %s failed for %s",
2669 port
->fp_instance
, op
, mod
->mod_info
->ulp_name
);
2677 ulp_port
->port_dstate
|= ULP_PORT_ATTACH
;
2681 ulp_port
->port_dstate
&= ~ULP_PORT_SUSPEND
;
2684 case FC_CMD_POWER_UP
:
2685 ulp_port
->port_dstate
&= ~ULP_PORT_POWER_DOWN
;
2688 mutex_exit(&ulp_port
->port_mutex
);
2693 fctl_detach_ulps(fc_local_port_t
*port
, fc_detach_cmd_t cmd
,
2694 struct modlinkage
*linkage
)
2696 int rval
= FC_SUCCESS
;
2697 fc_ulp_module_t
*mod
;
2698 fc_ulp_port_info_t info
;
2699 fc_ulp_ports_t
*ulp_port
;
2701 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
2703 info
.port_linkage
= linkage
;
2704 info
.port_dip
= port
->fp_port_dip
;
2705 info
.port_handle
= (opaque_t
)port
;
2706 info
.port_acc_attr
= port
->fp_fca_tran
->fca_acc_attr
;
2707 info
.port_fca_pkt_size
= port
->fp_fca_tran
->fca_pkt_size
;
2709 rw_enter(&fctl_ulp_lock
, RW_READER
);
2710 rw_enter(&fctl_mod_ports_lock
, RW_READER
);
2712 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
2713 if ((ulp_port
= fctl_get_ulp_port(mod
, port
)) == NULL
) {
2717 if (fctl_pre_detach(ulp_port
, cmd
) != FC_SUCCESS
) {
2721 fctl_init_dma_attr(port
, mod
, &info
);
2723 rval
= mod
->mod_info
->ulp_port_detach(
2724 mod
->mod_info
->ulp_handle
, &info
, cmd
);
2726 fctl_post_detach(mod
, ulp_port
, cmd
, rval
);
2728 if (rval
!= FC_SUCCESS
) {
2732 if (cmd
== FC_CMD_DETACH
&& strcmp(mod
->mod_info
->ulp_name
,
2734 ASSERT(ddi_get_driver_private(info
.port_dip
) == NULL
);
2737 mutex_enter(&ulp_port
->port_mutex
);
2738 ulp_port
->port_statec
= FC_ULP_STATEC_DONT_CARE
;
2739 mutex_exit(&ulp_port
->port_mutex
);
2742 rw_exit(&fctl_mod_ports_lock
);
2743 rw_exit(&fctl_ulp_lock
);
2749 fctl_init_dma_attr(fc_local_port_t
*port
, fc_ulp_module_t
*mod
,
2750 fc_ulp_port_info_t
*info
)
2753 if ((strcmp(mod
->mod_info
->ulp_name
, "fcp") == 0) ||
2754 (strcmp(mod
->mod_info
->ulp_name
, "ltct") == 0)) {
2755 info
->port_cmd_dma_attr
=
2756 port
->fp_fca_tran
->fca_dma_fcp_cmd_attr
;
2757 info
->port_data_dma_attr
=
2758 port
->fp_fca_tran
->fca_dma_fcp_data_attr
;
2759 info
->port_resp_dma_attr
=
2760 port
->fp_fca_tran
->fca_dma_fcp_rsp_attr
;
2761 } else if (strcmp(mod
->mod_info
->ulp_name
, "fcsm") == 0) {
2762 info
->port_cmd_dma_attr
=
2763 port
->fp_fca_tran
->fca_dma_fcsm_cmd_attr
;
2764 info
->port_data_dma_attr
=
2765 port
->fp_fca_tran
->fca_dma_attr
;
2766 info
->port_resp_dma_attr
=
2767 port
->fp_fca_tran
->fca_dma_fcsm_rsp_attr
;
2768 } else if (strcmp(mod
->mod_info
->ulp_name
, "fcip") == 0) {
2769 info
->port_cmd_dma_attr
=
2770 port
->fp_fca_tran
->fca_dma_fcip_cmd_attr
;
2771 info
->port_data_dma_attr
=
2772 port
->fp_fca_tran
->fca_dma_attr
;
2773 info
->port_resp_dma_attr
=
2774 port
->fp_fca_tran
->fca_dma_fcip_rsp_attr
;
2776 info
->port_cmd_dma_attr
= info
->port_data_dma_attr
=
2777 info
->port_resp_dma_attr
=
2778 port
->fp_fca_tran
->fca_dma_attr
; /* default */
2783 fctl_pre_detach(fc_ulp_ports_t
*ulp_port
, fc_detach_cmd_t cmd
)
2785 int rval
= FC_SUCCESS
;
2787 mutex_enter(&ulp_port
->port_mutex
);
2791 if ((ulp_port
->port_dstate
& ULP_PORT_ATTACH
) == 0) {
2796 case FC_CMD_SUSPEND
:
2797 if (!(ulp_port
->port_dstate
& ULP_PORT_ATTACH
) ||
2798 ulp_port
->port_dstate
& ULP_PORT_SUSPEND
) {
2803 case FC_CMD_POWER_DOWN
:
2804 if (!(ulp_port
->port_dstate
& ULP_PORT_ATTACH
) ||
2805 ulp_port
->port_dstate
& ULP_PORT_POWER_DOWN
) {
2811 if (rval
== FC_SUCCESS
) {
2812 ulp_port
->port_dstate
|= ULP_PORT_BUSY
;
2814 mutex_exit(&ulp_port
->port_mutex
);
2821 fctl_post_detach(fc_ulp_module_t
*mod
, fc_ulp_ports_t
*ulp_port
,
2822 fc_detach_cmd_t cmd
, int rval
)
2824 ASSERT(cmd
== FC_CMD_DETACH
|| cmd
== FC_CMD_SUSPEND
||
2825 cmd
== FC_CMD_POWER_DOWN
);
2827 mutex_enter(&ulp_port
->port_mutex
);
2828 ulp_port
->port_dstate
&= ~ULP_PORT_BUSY
;
2830 if (rval
!= FC_SUCCESS
) {
2832 fc_local_port_t
*port
= ulp_port
->port_handle
;
2834 mutex_exit(&ulp_port
->port_mutex
);
2841 case FC_CMD_SUSPEND
:
2845 case FC_CMD_POWER_DOWN
:
2850 cmn_err(CE_WARN
, "!fctl(%d): %s failed for %s",
2851 port
->fp_instance
, op
, mod
->mod_info
->ulp_name
);
2858 ulp_port
->port_dstate
&= ~ULP_PORT_ATTACH
;
2861 case FC_CMD_SUSPEND
:
2862 ulp_port
->port_dstate
|= ULP_PORT_SUSPEND
;
2865 case FC_CMD_POWER_DOWN
:
2866 ulp_port
->port_dstate
|= ULP_PORT_POWER_DOWN
;
2869 mutex_exit(&ulp_port
->port_mutex
);
2873 static fc_ulp_ports_t
*
2874 fctl_add_ulp_port(fc_ulp_module_t
*ulp_module
, fc_local_port_t
*port_handle
,
2877 fc_ulp_ports_t
*last
;
2878 fc_ulp_ports_t
*next
;
2879 fc_ulp_ports_t
*new;
2881 ASSERT(RW_READ_HELD(&fctl_ulp_lock
));
2882 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock
));
2885 next
= ulp_module
->mod_ports
;
2887 while (next
!= NULL
) {
2889 next
= next
->port_next
;
2892 new = fctl_alloc_ulp_port(sleep
);
2897 new->port_handle
= port_handle
;
2899 ulp_module
->mod_ports
= new;
2901 last
->port_next
= new;
2908 static fc_ulp_ports_t
*
2909 fctl_alloc_ulp_port(int sleep
)
2911 fc_ulp_ports_t
*new;
2913 new = kmem_zalloc(sizeof (*new), sleep
);
2917 mutex_init(&new->port_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
2924 fctl_remove_ulp_port(struct ulp_module
*ulp_module
,
2925 fc_local_port_t
*port_handle
)
2927 fc_ulp_ports_t
*last
;
2928 fc_ulp_ports_t
*next
;
2930 ASSERT(RW_WRITE_HELD(&fctl_ulp_lock
));
2931 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock
));
2934 next
= ulp_module
->mod_ports
;
2936 while (next
!= NULL
) {
2937 if (next
->port_handle
== port_handle
) {
2938 if (next
->port_dstate
& ULP_PORT_ATTACH
) {
2939 return (FC_FAILURE
);
2944 next
= next
->port_next
;
2948 ASSERT((next
->port_dstate
& ULP_PORT_ATTACH
) == 0);
2951 ulp_module
->mod_ports
= next
->port_next
;
2953 last
->port_next
= next
->port_next
;
2955 fctl_dealloc_ulp_port(next
);
2957 return (FC_SUCCESS
);
2959 return (FC_FAILURE
);
2965 fctl_dealloc_ulp_port(fc_ulp_ports_t
*next
)
2967 mutex_destroy(&next
->port_mutex
);
2968 kmem_free(next
, sizeof (*next
));
2972 static fc_ulp_ports_t
*
2973 fctl_get_ulp_port(struct ulp_module
*ulp_module
, fc_local_port_t
*port_handle
)
2975 fc_ulp_ports_t
*next
;
2977 ASSERT(RW_LOCK_HELD(&fctl_ulp_lock
));
2978 ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock
));
2980 for (next
= ulp_module
->mod_ports
; next
!= NULL
;
2981 next
= next
->port_next
) {
2982 if (next
->port_handle
== port_handle
) {
2992 * Pass state change notfications on to registered ULPs.
2994 * Can issue wakeups to client callers who might be waiting for completions
2997 * Caution: will silently deallocate any fc_remote_port_t and/or
2998 * fc_remote_node_t structs it finds that are not in use.
3001 fctl_ulp_statec_cb(void *arg
)
3005 fc_local_port_t
*port
;
3006 fc_ulp_ports_t
*ulp_port
;
3007 fc_ulp_module_t
*mod
;
3008 fc_port_clist_t
*clist
= (fc_port_clist_t
*)arg
;
3010 ASSERT(clist
!= NULL
);
3012 port
= clist
->clist_port
;
3014 mutex_enter(&port
->fp_mutex
);
3015 s_id
= port
->fp_port_id
.port_id
;
3016 mutex_exit(&port
->fp_mutex
);
3018 switch (clist
->clist_state
) {
3019 case FC_STATE_ONLINE
:
3020 new_state
= FC_ULP_STATEC_ONLINE
;
3023 case FC_STATE_OFFLINE
:
3024 if (clist
->clist_len
) {
3025 new_state
= FC_ULP_STATEC_OFFLINE_TIMEOUT
;
3027 new_state
= FC_ULP_STATEC_OFFLINE
;
3032 new_state
= FC_ULP_STATEC_DONT_CARE
;
3038 * sanity check for presence of OLD devices in the hash lists
3040 if (clist
->clist_size
) {
3042 fc_remote_port_t
*pd
;
3044 ASSERT(clist
->clist_map
!= NULL
);
3045 for (count
= 0; count
< clist
->clist_len
; count
++) {
3046 if (clist
->clist_map
[count
].map_state
==
3047 PORT_DEVICE_INVALID
) {
3051 pd
= clist
->clist_map
[count
].map_pd
;
3053 mutex_enter(&pd
->pd_mutex
);
3054 pwwn
= pd
->pd_port_name
;
3055 d_id
= pd
->pd_port_id
;
3056 mutex_exit(&pd
->pd_mutex
);
3058 pd
= fctl_get_remote_port_by_pwwn(port
,
3061 ASSERT(pd
!= clist
->clist_map
[count
].
3064 pd
= fctl_get_remote_port_by_did(port
,
3066 ASSERT(pd
!= clist
->clist_map
[count
].
3075 * Check for duplicate map entries
3077 if (clist
->clist_size
) {
3079 fc_remote_port_t
*pd1
, *pd2
;
3081 ASSERT(clist
->clist_map
!= NULL
);
3082 for (count
= 0; count
< clist
->clist_len
-1; count
++) {
3085 pd1
= clist
->clist_map
[count
].map_pd
;
3090 for (count2
= count
+1;
3091 count2
< clist
->clist_len
;
3094 pd2
= clist
->clist_map
[count2
].map_pd
;
3100 clist
->clist_map
[count
].map_flags
|=
3101 PORT_DEVICE_DUPLICATE_MAP_ENTRY
;
3109 rw_enter(&fctl_ulp_lock
, RW_READER
);
3110 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
3111 rw_enter(&fctl_mod_ports_lock
, RW_READER
);
3112 ulp_port
= fctl_get_ulp_port(mod
, port
);
3113 rw_exit(&fctl_mod_ports_lock
);
3115 if (ulp_port
== NULL
) {
3119 mutex_enter(&ulp_port
->port_mutex
);
3120 if (FCTL_DISALLOW_CALLBACKS(ulp_port
->port_dstate
)) {
3121 mutex_exit(&ulp_port
->port_mutex
);
3125 switch (ulp_port
->port_statec
) {
3126 case FC_ULP_STATEC_DONT_CARE
:
3127 if (ulp_port
->port_statec
!= new_state
) {
3128 ulp_port
->port_statec
= new_state
;
3132 case FC_ULP_STATEC_ONLINE
:
3133 case FC_ULP_STATEC_OFFLINE
:
3134 if (ulp_port
->port_statec
== new_state
) {
3135 mutex_exit(&ulp_port
->port_mutex
);
3138 ulp_port
->port_statec
= new_state
;
3141 case FC_ULP_STATEC_OFFLINE_TIMEOUT
:
3142 if (ulp_port
->port_statec
== new_state
||
3143 new_state
== FC_ULP_STATEC_OFFLINE
) {
3144 mutex_exit(&ulp_port
->port_mutex
);
3147 ulp_port
->port_statec
= new_state
;
3155 mod
->mod_info
->ulp_statec_callback(
3156 mod
->mod_info
->ulp_handle
, (opaque_t
)port
,
3157 clist
->clist_state
, clist
->clist_flags
,
3158 clist
->clist_map
, clist
->clist_len
, s_id
);
3160 mutex_exit(&ulp_port
->port_mutex
);
3162 rw_exit(&fctl_ulp_lock
);
3164 if (clist
->clist_size
) {
3166 fc_remote_node_t
*node
;
3167 fc_remote_port_t
*pd
;
3169 ASSERT(clist
->clist_map
!= NULL
);
3170 for (count
= 0; count
< clist
->clist_len
; count
++) {
3172 if ((pd
= clist
->clist_map
[count
].map_pd
) == NULL
) {
3176 mutex_enter(&pd
->pd_mutex
);
3179 ASSERT(pd
->pd_ref_count
>= 0);
3181 if (clist
->clist_map
[count
].map_state
!=
3182 PORT_DEVICE_INVALID
) {
3183 mutex_exit(&pd
->pd_mutex
);
3187 node
= pd
->pd_remote_nodep
;
3188 pd
->pd_aux_flags
&= ~PD_GIVEN_TO_ULPS
;
3190 mutex_exit(&pd
->pd_mutex
);
3193 * This fc_remote_port_t is no longer referenced
3194 * by any ULPs. Deallocate it if its pd_ref_count
3197 if ((fctl_destroy_remote_port(port
, pd
) == 0) &&
3199 fctl_destroy_remote_node(node
);
3203 kmem_free(clist
->clist_map
,
3204 sizeof (*(clist
->clist_map
)) * clist
->clist_size
);
3207 if (clist
->clist_wait
) {
3208 mutex_enter(&clist
->clist_mutex
);
3209 clist
->clist_wait
= 0;
3210 cv_signal(&clist
->clist_cv
);
3211 mutex_exit(&clist
->clist_mutex
);
3213 kmem_free(clist
, sizeof (*clist
));
3219 * Allocate an fc_remote_node_t struct to represent a remote node for the
3220 * given nwwn. This will also add the nwwn to the global nwwn table.
3222 * Returns a pointer to the newly-allocated struct. Returns NULL if
3223 * the kmem_zalloc fails or if the enlist_wwn attempt fails.
3226 fctl_create_remote_node(la_wwn_t
*nwwn
, int sleep
)
3228 fc_remote_node_t
*rnodep
;
3230 if ((rnodep
= kmem_zalloc(sizeof (*rnodep
), sleep
)) == NULL
) {
3234 mutex_init(&rnodep
->fd_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
3236 rnodep
->fd_node_name
= *nwwn
;
3237 rnodep
->fd_flags
= FC_REMOTE_NODE_VALID
;
3238 rnodep
->fd_numports
= 1;
3240 if (fctl_enlist_nwwn_table(rnodep
, sleep
) != FC_SUCCESS
) {
3241 mutex_destroy(&rnodep
->fd_mutex
);
3242 kmem_free(rnodep
, sizeof (*rnodep
));
3250 * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
3251 * Silently skips the deconstruct/free if there are any fc_remote_port_t
3252 * (remote port device) structs still referenced by the given
3253 * fc_remote_node_t struct.
3256 fctl_destroy_remote_node(fc_remote_node_t
*rnodep
)
3258 mutex_enter(&rnodep
->fd_mutex
);
3261 * Look at the count and linked list of of remote ports
3262 * (fc_remote_port_t structs); bail if these indicate that
3263 * given fc_remote_node_t may be in use.
3265 if (rnodep
->fd_numports
!= 0 || rnodep
->fd_portlistp
) {
3266 mutex_exit(&rnodep
->fd_mutex
);
3270 mutex_exit(&rnodep
->fd_mutex
);
3272 mutex_destroy(&rnodep
->fd_mutex
);
3273 kmem_free(rnodep
, sizeof (*rnodep
));
3278 * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
3279 * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3280 * This only fails if the kmem_zalloc fails. This does not check for a
3281 * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
3282 * This is only called from fctl_create_remote_node().
3285 fctl_enlist_nwwn_table(fc_remote_node_t
*rnodep
, int sleep
)
3288 fctl_nwwn_elem_t
*new;
3289 fctl_nwwn_list_t
*head
;
3291 ASSERT(!MUTEX_HELD(&rnodep
->fd_mutex
));
3293 if ((new = kmem_zalloc(sizeof (*new), sleep
)) == NULL
) {
3294 return (FC_FAILURE
);
3297 mutex_enter(&fctl_nwwn_hash_mutex
);
3298 new->fne_nodep
= rnodep
;
3300 mutex_enter(&rnodep
->fd_mutex
);
3301 ASSERT(fctl_is_wwn_zero(&rnodep
->fd_node_name
) == FC_FAILURE
);
3302 index
= HASH_FUNC(WWN_HASH_KEY(rnodep
->fd_node_name
.raw_wwn
),
3303 fctl_nwwn_table_size
);
3304 mutex_exit(&rnodep
->fd_mutex
);
3306 head
= &fctl_nwwn_hash_table
[index
];
3308 /* Link it in at the head of the hash list */
3309 new->fne_nextp
= head
->fnl_headp
;
3310 head
->fnl_headp
= new;
3312 mutex_exit(&fctl_nwwn_hash_mutex
);
3314 return (FC_SUCCESS
);
3319 * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
3320 * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3323 fctl_delist_nwwn_table(fc_remote_node_t
*rnodep
)
3326 fctl_nwwn_list_t
*head
;
3327 fctl_nwwn_elem_t
*elem
;
3328 fctl_nwwn_elem_t
*prev
;
3330 ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex
));
3331 ASSERT(MUTEX_HELD(&rnodep
->fd_mutex
));
3333 index
= HASH_FUNC(WWN_HASH_KEY(rnodep
->fd_node_name
.raw_wwn
),
3334 fctl_nwwn_table_size
);
3336 head
= &fctl_nwwn_hash_table
[index
];
3337 elem
= head
->fnl_headp
;
3340 while (elem
!= NULL
) {
3341 if (elem
->fne_nodep
== rnodep
) {
3343 * Found it -- unlink it from the list & decrement
3344 * the count for the hash chain.
3347 head
->fnl_headp
= elem
->fne_nextp
;
3349 prev
->fne_nextp
= elem
->fne_nextp
;
3354 elem
= elem
->fne_nextp
;
3358 kmem_free(elem
, sizeof (*elem
));
3364 * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3365 * Looks in the global fctl_nwwn_hash_table[]. Identical to the
3366 * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
3367 * the fc_count reference count in the f_device_t before returning.
3369 * This function is called by: fctl_create_remote_port_t().
3372 * Note: The calling thread needs to make sure it isn't holding any device
3373 * mutex (more so the fc_remote_node_t that could potentially have this wwn).
3376 fctl_get_remote_node_by_nwwn(la_wwn_t
*node_wwn
)
3379 fctl_nwwn_elem_t
*elem
;
3380 fc_remote_node_t
*next
;
3381 fc_remote_node_t
*rnodep
= NULL
;
3383 index
= HASH_FUNC(WWN_HASH_KEY(node_wwn
->raw_wwn
),
3384 fctl_nwwn_table_size
);
3385 ASSERT(index
>= 0 && index
< fctl_nwwn_table_size
);
3387 mutex_enter(&fctl_nwwn_hash_mutex
);
3388 elem
= fctl_nwwn_hash_table
[index
].fnl_headp
;
3389 while (elem
!= NULL
) {
3390 next
= elem
->fne_nodep
;
3392 mutex_enter(&next
->fd_mutex
);
3393 if (fctl_wwn_cmp(node_wwn
, &next
->fd_node_name
) == 0) {
3395 mutex_exit(&next
->fd_mutex
);
3398 mutex_exit(&next
->fd_mutex
);
3400 elem
= elem
->fne_nextp
;
3402 mutex_exit(&fctl_nwwn_hash_mutex
);
3409 * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3410 * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
3411 * reference count in the f_device_t before returning.
3413 * This function is only called by fctl_create_remote_port_t().
3416 fctl_lock_remote_node_by_nwwn(la_wwn_t
*node_wwn
)
3419 fctl_nwwn_elem_t
*elem
;
3420 fc_remote_node_t
*next
;
3421 fc_remote_node_t
*rnodep
= NULL
;
3423 index
= HASH_FUNC(WWN_HASH_KEY(node_wwn
->raw_wwn
),
3424 fctl_nwwn_table_size
);
3425 ASSERT(index
>= 0 && index
< fctl_nwwn_table_size
);
3427 mutex_enter(&fctl_nwwn_hash_mutex
);
3428 elem
= fctl_nwwn_hash_table
[index
].fnl_headp
;
3429 while (elem
!= NULL
) {
3430 next
= elem
->fne_nodep
;
3432 mutex_enter(&next
->fd_mutex
);
3433 if (fctl_wwn_cmp(node_wwn
, &next
->fd_node_name
) == 0) {
3435 rnodep
->fd_numports
++;
3436 mutex_exit(&next
->fd_mutex
);
3439 mutex_exit(&next
->fd_mutex
);
3441 elem
= elem
->fne_nextp
;
3443 mutex_exit(&fctl_nwwn_hash_mutex
);
3450 * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
3451 * the newly allocated struct. Only fails if the kmem_zalloc() fails.
3454 fctl_alloc_remote_port(fc_local_port_t
*port
, la_wwn_t
*port_wwn
,
3455 uint32_t d_id
, uchar_t recepient
, int sleep
)
3457 fc_remote_port_t
*pd
;
3459 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3460 ASSERT(FC_IS_REAL_DEVICE(d_id
));
3462 if ((pd
= kmem_zalloc(sizeof (*pd
), sleep
)) == NULL
) {
3465 fctl_tc_constructor(&pd
->pd_logo_tc
, FC_LOGO_TOLERANCE_LIMIT
,
3466 FC_LOGO_TOLERANCE_TIME_LIMIT
);
3468 mutex_init(&pd
->pd_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
3470 pd
->pd_port_id
.port_id
= d_id
;
3471 pd
->pd_port_name
= *port_wwn
;
3473 pd
->pd_state
= PORT_DEVICE_VALID
;
3474 pd
->pd_type
= PORT_DEVICE_NEW
;
3475 pd
->pd_recepient
= recepient
;
3482 * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
3485 fctl_dealloc_remote_port(fc_remote_port_t
*pd
)
3487 ASSERT(!MUTEX_HELD(&pd
->pd_mutex
));
3489 fctl_tc_destructor(&pd
->pd_logo_tc
);
3490 mutex_destroy(&pd
->pd_mutex
);
3491 kmem_free(pd
, sizeof (*pd
));
3495 * Add the given fc_remote_port_t onto the linked list of remote port
3496 * devices associated with the given fc_remote_node_t. Does NOT add the
3497 * fc_remote_port_t to the list if already exists on the list.
3500 fctl_link_remote_port_to_remote_node(fc_remote_node_t
*rnodep
,
3501 fc_remote_port_t
*pd
)
3503 fc_remote_port_t
*last
;
3504 fc_remote_port_t
*ports
;
3506 mutex_enter(&rnodep
->fd_mutex
);
3509 for (ports
= rnodep
->fd_portlistp
; ports
!= NULL
;
3510 ports
= ports
->pd_port_next
) {
3513 * The given fc_remote_port_t is already on the linked
3514 * list chain for the given remote node, so bail now.
3516 mutex_exit(&rnodep
->fd_mutex
);
3522 /* Add the fc_remote_port_t to the tail of the linked list */
3524 last
->pd_port_next
= pd
;
3526 rnodep
->fd_portlistp
= pd
;
3528 pd
->pd_port_next
= NULL
;
3531 * Link the fc_remote_port_t back to the associated fc_remote_node_t.
3533 mutex_enter(&pd
->pd_mutex
);
3534 pd
->pd_remote_nodep
= rnodep
;
3535 mutex_exit(&pd
->pd_mutex
);
3537 mutex_exit(&rnodep
->fd_mutex
);
3542 * Remove the specified fc_remote_port_t from the linked list of remote ports
3543 * for the given fc_remote_node_t.
3545 * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
3546 * list of the fc_remote_node_t.
3548 * The fd_numports on the given fc_remote_node_t is decremented, and if
3549 * it hits zero then this function also removes the fc_remote_node_t from the
3550 * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
3551 * are removed from the fctl_nwwn_hash_table[].
3554 fctl_unlink_remote_port_from_remote_node(fc_remote_node_t
*rnodep
,
3555 fc_remote_port_t
*pd
)
3558 fc_remote_port_t
*last
;
3559 fc_remote_port_t
*ports
;
3561 ASSERT(!MUTEX_HELD(&rnodep
->fd_mutex
));
3562 ASSERT(!MUTEX_HELD(&pd
->pd_mutex
));
3566 mutex_enter(&fctl_nwwn_hash_mutex
);
3568 mutex_enter(&rnodep
->fd_mutex
);
3571 * Go thru the linked list of fc_remote_port_t structs for the given
3572 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
3574 ports
= rnodep
->fd_portlistp
;
3575 while (ports
!= NULL
) {
3577 break; /* Found the requested fc_remote_port_t */
3580 ports
= ports
->pd_port_next
;
3584 rcount
= --rnodep
->fd_numports
;
3586 /* Note: this is only ever called from here */
3587 fctl_delist_nwwn_table(rnodep
);
3590 last
->pd_port_next
= pd
->pd_port_next
;
3592 rnodep
->fd_portlistp
= pd
->pd_port_next
;
3594 mutex_enter(&pd
->pd_mutex
);
3595 pd
->pd_remote_nodep
= NULL
;
3596 mutex_exit(&pd
->pd_mutex
);
3599 pd
->pd_port_next
= NULL
;
3601 mutex_exit(&rnodep
->fd_mutex
);
3602 mutex_exit(&fctl_nwwn_hash_mutex
);
3609 * Add the given fc_remote_port_t struct to the d_id table in the given
3610 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
3613 * No memory allocs are required, so this never fails, but it does use the
3614 * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
3615 * (There does not seem to be a way to tell the caller that a duplicate
3619 fctl_enlist_did_table(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
3621 struct d_id_hash
*head
;
3623 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3624 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
3626 if (pd
->pd_aux_flags
& PD_IN_DID_QUEUE
) {
3630 head
= &port
->fp_did_table
[D_ID_HASH_FUNC(pd
->pd_port_id
.port_id
,
3636 fc_remote_port_t
*tmp_pd
;
3637 struct d_id_hash
*tmp_head
;
3640 * Search down in each bucket for a duplicate pd
3641 * Also search for duplicate D_IDs
3642 * This DEBUG code will force an ASSERT if a duplicate
3645 for (index
= 0; index
< did_table_size
; index
++) {
3646 tmp_head
= &port
->fp_did_table
[index
];
3648 tmp_pd
= tmp_head
->d_id_head
;
3649 while (tmp_pd
!= NULL
) {
3650 ASSERT(tmp_pd
!= pd
);
3652 if (tmp_pd
->pd_state
!= PORT_DEVICE_INVALID
&&
3653 tmp_pd
->pd_type
!= PORT_DEVICE_OLD
) {
3654 ASSERT(tmp_pd
->pd_port_id
.port_id
!=
3655 pd
->pd_port_id
.port_id
);
3658 tmp_pd
= tmp_pd
->pd_did_hnext
;
3663 bzero(pd
->pd_d_stack
, sizeof (pd
->pd_d_stack
));
3664 pd
->pd_d_depth
= getpcstack(pd
->pd_d_stack
, FC_STACK_DEPTH
);
3667 pd
->pd_did_hnext
= head
->d_id_head
;
3668 head
->d_id_head
= pd
;
3670 pd
->pd_aux_flags
|= PD_IN_DID_QUEUE
;
3676 * Remove the given fc_remote_port_t struct from the d_id table in the given
3677 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the
3680 * Does nothing if the requested fc_remote_port_t was not found.
3683 fctl_delist_did_table(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
3686 struct d_id_hash
*head
;
3687 fc_remote_port_t
*pd_next
;
3688 fc_remote_port_t
*last
;
3690 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3691 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
3693 d_id
= pd
->pd_port_id
.port_id
;
3694 head
= &port
->fp_did_table
[D_ID_HASH_FUNC(d_id
, did_table_size
)];
3696 pd_next
= head
->d_id_head
;
3698 while (pd_next
!= NULL
) {
3699 if (pd
== pd_next
) {
3700 break; /* Found the given fc_remote_port_t */
3703 pd_next
= pd_next
->pd_did_hnext
;
3708 * Found the given fc_remote_port_t; now remove it from the
3713 head
->d_id_head
= pd
->pd_did_hnext
;
3715 last
->pd_did_hnext
= pd
->pd_did_hnext
;
3717 pd
->pd_aux_flags
&= ~PD_IN_DID_QUEUE
;
3718 pd
->pd_did_hnext
= NULL
;
3724 * Add the given fc_remote_port_t struct to the pwwn table in the given
3725 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
3726 * in the fc_remote_port_t.
3728 * No memory allocs are required, so this never fails.
3731 fctl_enlist_pwwn_table(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
3734 struct pwwn_hash
*head
;
3736 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3737 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
3739 ASSERT(fctl_is_wwn_zero(&pd
->pd_port_name
) == FC_FAILURE
);
3741 index
= HASH_FUNC(WWN_HASH_KEY(pd
->pd_port_name
.raw_wwn
),
3744 head
= &port
->fp_pwwn_table
[index
];
3749 fc_remote_port_t
*tmp_pd
;
3750 struct pwwn_hash
*tmp_head
;
3753 * Search down in each bucket for a duplicate pd
3754 * Search also for a duplicate WWN
3755 * Throw an ASSERT if any duplicate is found.
3757 for (index
= 0; index
< pwwn_table_size
; index
++) {
3758 tmp_head
= &port
->fp_pwwn_table
[index
];
3760 tmp_pd
= tmp_head
->pwwn_head
;
3761 while (tmp_pd
!= NULL
) {
3762 ASSERT(tmp_pd
!= pd
);
3764 if (tmp_pd
->pd_state
!= PORT_DEVICE_INVALID
&&
3765 tmp_pd
->pd_type
!= PORT_DEVICE_OLD
) {
3766 ASSERT(fctl_wwn_cmp(
3767 &tmp_pd
->pd_port_name
,
3768 &pd
->pd_port_name
) != 0);
3771 tmp_pd
= tmp_pd
->pd_wwn_hnext
;
3776 bzero(pd
->pd_w_stack
, sizeof (pd
->pd_w_stack
));
3777 pd
->pd_w_depth
= getpcstack(pd
->pd_w_stack
, FC_STACK_DEPTH
);
3780 pd
->pd_wwn_hnext
= head
->pwwn_head
;
3781 head
->pwwn_head
= pd
;
3785 * Make sure we tie fp_dev_count to the size of the
3788 port
->fp_dev_count
++;
3793 * Remove the given fc_remote_port_t struct from the pwwn table in the given
3794 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn
3795 * in the fc_remote_port_t.
3797 * Does nothing if the requested fc_remote_port_t was not found.
3800 fctl_delist_pwwn_table(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
3804 struct pwwn_hash
*head
;
3805 fc_remote_port_t
*pd_next
;
3806 fc_remote_port_t
*last
;
3808 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3809 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
3811 pwwn
= pd
->pd_port_name
;
3812 index
= HASH_FUNC(WWN_HASH_KEY(pwwn
.raw_wwn
), pwwn_table_size
);
3814 head
= &port
->fp_pwwn_table
[index
];
3817 pd_next
= head
->pwwn_head
;
3818 while (pd_next
!= NULL
) {
3819 if (pd_next
== pd
) {
3820 break; /* Found the given fc_remote_port_t */
3823 pd_next
= pd_next
->pd_wwn_hnext
;
3828 * Found the given fc_remote_port_t; now remove it from the
3833 * Make sure we tie fp_dev_count to the size of the
3836 port
->fp_dev_count
--;
3838 head
->pwwn_head
= pd
->pd_wwn_hnext
;
3840 last
->pd_wwn_hnext
= pd
->pd_wwn_hnext
;
3842 pd
->pd_wwn_hnext
= NULL
;
3848 * Looks in the d_id table of the specified fc_local_port_t for the
3849 * fc_remote_port_t that matches the given d_id. Hashes based upon
3851 * Returns a pointer to the fc_remote_port_t struct, but does not update any
3852 * reference counts or otherwise indicate that the fc_remote_port_t is in
3856 fctl_get_remote_port_by_did(fc_local_port_t
*port
, uint32_t d_id
)
3858 struct d_id_hash
*head
;
3859 fc_remote_port_t
*pd
;
3861 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
3863 mutex_enter(&port
->fp_mutex
);
3865 head
= &port
->fp_did_table
[D_ID_HASH_FUNC(d_id
, did_table_size
)];
3867 pd
= head
->d_id_head
;
3868 while (pd
!= NULL
) {
3869 mutex_enter(&pd
->pd_mutex
);
3870 if (pd
->pd_port_id
.port_id
== d_id
) {
3871 /* Match found -- break out of the loop */
3872 mutex_exit(&pd
->pd_mutex
);
3875 mutex_exit(&pd
->pd_mutex
);
3876 pd
= pd
->pd_did_hnext
;
3879 mutex_exit(&port
->fp_mutex
);
3885 #ifndef __lock_lint /* uncomment when there is a consumer */
3888 fc_ulp_hold_remote_port(opaque_t port_handle
)
3890 fc_remote_port_t
*pd
= port_handle
;
3892 mutex_enter(&pd
->pd_mutex
);
3894 mutex_exit(&pd
->pd_mutex
);
3898 * Looks in the d_id table of the specified fc_local_port_t for the
3899 * fc_remote_port_t that matches the given d_id. Hashes based upon
3900 * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3902 * Increments pd_ref_count in the fc_remote_port_t if the
3903 * fc_remote_port_t is found at the given d_id.
3905 * The fc_remote_port_t is ignored (treated as non-existent) if either
3906 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3909 fctl_hold_remote_port_by_did(fc_local_port_t
*port
, uint32_t d_id
)
3911 struct d_id_hash
*head
;
3912 fc_remote_port_t
*pd
;
3914 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
3916 mutex_enter(&port
->fp_mutex
);
3918 head
= &port
->fp_did_table
[D_ID_HASH_FUNC(d_id
, did_table_size
)];
3920 pd
= head
->d_id_head
;
3921 while (pd
!= NULL
) {
3922 mutex_enter(&pd
->pd_mutex
);
3923 if (pd
->pd_port_id
.port_id
== d_id
&& pd
->pd_state
!=
3924 PORT_DEVICE_INVALID
&& pd
->pd_type
!= PORT_DEVICE_OLD
) {
3925 ASSERT(pd
->pd_ref_count
>= 0);
3927 mutex_exit(&pd
->pd_mutex
);
3930 mutex_exit(&pd
->pd_mutex
);
3931 pd
= pd
->pd_did_hnext
;
3934 mutex_exit(&port
->fp_mutex
);
3939 #endif /* __lock_lint */
3942 * Looks in the pwwn table of the specified fc_local_port_t for the
3943 * fc_remote_port_t that matches the given pwwn. Hashes based upon the
3944 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3945 * but does not update any reference counts or otherwise indicate that
3946 * the fc_remote_port_t is in use.
3949 fctl_get_remote_port_by_pwwn(fc_local_port_t
*port
, la_wwn_t
*pwwn
)
3952 struct pwwn_hash
*head
;
3953 fc_remote_port_t
*pd
;
3955 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
3957 mutex_enter(&port
->fp_mutex
);
3959 index
= HASH_FUNC(WWN_HASH_KEY(pwwn
->raw_wwn
), pwwn_table_size
);
3960 head
= &port
->fp_pwwn_table
[index
];
3962 pd
= head
->pwwn_head
;
3963 while (pd
!= NULL
) {
3964 mutex_enter(&pd
->pd_mutex
);
3965 if (fctl_wwn_cmp(&pd
->pd_port_name
, pwwn
) == 0) {
3966 mutex_exit(&pd
->pd_mutex
);
3969 mutex_exit(&pd
->pd_mutex
);
3970 pd
= pd
->pd_wwn_hnext
;
3973 mutex_exit(&port
->fp_mutex
);
3980 * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
3981 * the caller already hold the fp_mutex in the fc_local_port_t struct.
3984 fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t
*port
, la_wwn_t
*pwwn
)
3987 struct pwwn_hash
*head
;
3988 fc_remote_port_t
*pd
;
3990 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
3992 index
= HASH_FUNC(WWN_HASH_KEY(pwwn
->raw_wwn
), pwwn_table_size
);
3993 head
= &port
->fp_pwwn_table
[index
];
3995 pd
= head
->pwwn_head
;
3996 while (pd
!= NULL
) {
3997 mutex_enter(&pd
->pd_mutex
);
3998 if (fctl_wwn_cmp(&pd
->pd_port_name
, pwwn
) == 0) {
3999 mutex_exit(&pd
->pd_mutex
);
4002 mutex_exit(&pd
->pd_mutex
);
4003 pd
= pd
->pd_wwn_hnext
;
4011 * Looks in the pwwn table of the specified fc_local_port_t for the
4012 * fc_remote_port_t that matches the given d_id. Hashes based upon the
4013 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
4015 * Increments pd_ref_count in the fc_remote_port_t if the
4016 * fc_remote_port_t is found at the given pwwn.
4018 * The fc_remote_port_t is ignored (treated as non-existent) if either
4019 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
4022 fctl_hold_remote_port_by_pwwn(fc_local_port_t
*port
, la_wwn_t
*pwwn
)
4025 struct pwwn_hash
*head
;
4026 fc_remote_port_t
*pd
;
4028 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
4030 mutex_enter(&port
->fp_mutex
);
4032 index
= HASH_FUNC(WWN_HASH_KEY(pwwn
->raw_wwn
), pwwn_table_size
);
4033 head
= &port
->fp_pwwn_table
[index
];
4035 pd
= head
->pwwn_head
;
4036 while (pd
!= NULL
) {
4037 mutex_enter(&pd
->pd_mutex
);
4038 if (fctl_wwn_cmp(&pd
->pd_port_name
, pwwn
) == 0 &&
4039 pd
->pd_state
!= PORT_DEVICE_INVALID
&&
4040 pd
->pd_type
!= PORT_DEVICE_OLD
) {
4041 ASSERT(pd
->pd_ref_count
>= 0);
4043 mutex_exit(&pd
->pd_mutex
);
4046 mutex_exit(&pd
->pd_mutex
);
4047 pd
= pd
->pd_wwn_hnext
;
4050 mutex_exit(&port
->fp_mutex
);
4057 * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
4060 * If pd_ref_count reaches zero, then this function will see if the
4061 * fc_remote_port_t has been marked for deallocation. If so (and also if there
4062 * are no other potential operations in progress, as indicated by the
4063 * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
4064 * fctl_destroy_remote_port_t() is called to deconstruct/free the given
4065 * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
4066 * on the associated fc_local_port_t). If the associated fc_remote_node_t is no
4067 * longer in use, then it too is deconstructed/freed.
4070 fctl_release_remote_port(fc_remote_port_t
*pd
)
4073 fc_remote_node_t
*node
;
4074 fc_local_port_t
*port
;
4076 mutex_enter(&pd
->pd_mutex
);
4079 ASSERT(pd
->pd_ref_count
> 0);
4081 if (pd
->pd_ref_count
== 0 &&
4082 (pd
->pd_aux_flags
& PD_NEEDS_REMOVAL
) &&
4083 (pd
->pd_flags
!= PD_ELS_IN_PROGRESS
) &&
4084 (pd
->pd_flags
!= PD_ELS_MARK
)) {
4086 pd
->pd_aux_flags
&= ~PD_NEEDS_REMOVAL
;
4088 node
= pd
->pd_remote_nodep
;
4089 ASSERT(node
!= NULL
);
4091 mutex_exit(&pd
->pd_mutex
);
4095 * The fc_remote_port_t struct has to go away now, so call the
4096 * cleanup function to get it off the various lists and remove
4097 * references to it in any other associated structs.
4099 if (fctl_destroy_remote_port(port
, pd
) == 0) {
4101 * No more fc_remote_port_t references found in the
4102 * associated fc_remote_node_t, so deallocate the
4103 * fc_remote_node_t (if it even exists).
4106 fctl_destroy_remote_node(node
);
4114 fctl_fillout_map(fc_local_port_t
*port
, fc_portmap_t
**map
, uint32_t *len
,
4115 int whole_map
, int justcopy
, int orphan
)
4122 struct pwwn_hash
*head
;
4123 fc_remote_port_t
*pd
;
4124 fc_remote_port_t
*old_pd
;
4125 fc_remote_port_t
*last_pd
;
4126 fc_portmap_t
*listptr
;
4128 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
4130 mutex_enter(&port
->fp_mutex
);
4132 topology
= port
->fp_topology
;
4135 ASSERT(!FC_IS_TOP_SWITCH(topology
));
4138 for (full_list
= listlen
= index
= 0;
4139 index
< pwwn_table_size
; index
++) {
4140 head
= &port
->fp_pwwn_table
[index
];
4141 pd
= head
->pwwn_head
;
4142 while (pd
!= NULL
) {
4144 mutex_enter(&pd
->pd_mutex
);
4145 if (pd
->pd_type
!= PORT_DEVICE_NOCHANGE
) {
4148 mutex_exit(&pd
->pd_mutex
);
4149 pd
= pd
->pd_wwn_hnext
;
4153 if (whole_map
== 0) {
4154 if (listlen
== 0 && *len
== 0) {
4157 mutex_exit(&port
->fp_mutex
);
4161 if (full_list
== 0 && *len
== 0) {
4164 mutex_exit(&port
->fp_mutex
);
4170 ASSERT(*map
== NULL
);
4171 if (whole_map
== 0) {
4172 listptr
= *map
= kmem_zalloc(
4173 sizeof (*listptr
) * listlen
, KM_SLEEP
);
4176 listptr
= *map
= kmem_zalloc(
4177 sizeof (*listptr
) * full_list
, KM_SLEEP
);
4182 * By design this routine mandates the callers to
4183 * ask for a whole map when they specify the length
4186 ASSERT(whole_map
== 1);
4187 if (*len
< full_list
) {
4189 mutex_exit(&port
->fp_mutex
);
4196 for (index
= 0; index
< pwwn_table_size
; index
++) {
4197 head
= &port
->fp_pwwn_table
[index
];
4199 pd
= head
->pwwn_head
;
4200 while (pd
!= NULL
) {
4201 mutex_enter(&pd
->pd_mutex
);
4202 if ((whole_map
== 0 &&
4203 pd
->pd_type
== PORT_DEVICE_NOCHANGE
) ||
4204 pd
->pd_state
== PORT_DEVICE_INVALID
) {
4205 mutex_exit(&pd
->pd_mutex
);
4207 pd
= pd
->pd_wwn_hnext
;
4210 mutex_exit(&pd
->pd_mutex
);
4212 fctl_copy_portmap(listptr
, pd
);
4216 pd
= pd
->pd_wwn_hnext
;
4221 mutex_enter(&pd
->pd_mutex
);
4222 ASSERT(pd
->pd_state
!= PORT_DEVICE_INVALID
);
4223 if (pd
->pd_type
== PORT_DEVICE_OLD
) {
4224 listptr
->map_pd
= pd
;
4225 listptr
->map_state
= pd
->pd_state
=
4226 PORT_DEVICE_INVALID
;
4228 * Remove this from the PWWN hash table.
4231 pd
= old_pd
->pd_wwn_hnext
;
4233 if (last_pd
== NULL
) {
4234 ASSERT(old_pd
== head
->pwwn_head
);
4236 head
->pwwn_head
= pd
;
4238 last_pd
->pd_wwn_hnext
= pd
;
4242 * Make sure we tie fp_dev_count to the size
4245 port
->fp_dev_count
--;
4246 old_pd
->pd_wwn_hnext
= NULL
;
4248 if (port
->fp_topology
== FC_TOP_PRIVATE_LOOP
&&
4249 port
->fp_statec_busy
&& !orphan
) {
4250 fctl_check_alpa_list(port
, old_pd
);
4254 * Remove if the port device has stealthily
4255 * present in the D_ID hash table
4257 fctl_delist_did_table(port
, old_pd
);
4259 ASSERT(old_pd
->pd_remote_nodep
!= NULL
);
4261 initiator
= (old_pd
->pd_recepient
==
4262 PD_PLOGI_INITIATOR
) ? 1 : 0;
4264 mutex_exit(&old_pd
->pd_mutex
);
4265 mutex_exit(&port
->fp_mutex
);
4268 fctl_print_if_not_orphan(port
, old_pd
);
4270 (void) fctl_add_orphan(port
, old_pd
,
4274 if (FC_IS_TOP_SWITCH(topology
) && initiator
) {
4275 (void) fctl_add_orphan(port
, old_pd
,
4278 mutex_enter(&port
->fp_mutex
);
4280 listptr
->map_pd
= pd
;
4281 pd
->pd_type
= PORT_DEVICE_NOCHANGE
;
4282 mutex_exit(&pd
->pd_mutex
);
4284 pd
= pd
->pd_wwn_hnext
;
4289 mutex_exit(&port
->fp_mutex
);
4294 fctl_alloc_job(int job_code
, int job_flags
, void (*comp
) (opaque_t
, uchar_t
),
4295 opaque_t arg
, int sleep
)
4299 job
= (job_request_t
*)kmem_cache_alloc(fctl_job_cache
, sleep
);
4301 job
->job_result
= FC_SUCCESS
;
4302 job
->job_code
= job_code
;
4303 job
->job_flags
= job_flags
;
4304 job
->job_cb_arg
= arg
;
4305 job
->job_comp
= comp
;
4306 job
->job_private
= NULL
;
4307 job
->job_ulp_pkts
= NULL
;
4308 job
->job_ulp_listlen
= 0;
4310 job
->job_counter
= 0;
4311 job
->job_next
= NULL
;
4312 #endif /* __lock_lint */
4320 fctl_dealloc_job(job_request_t
*job
)
4322 kmem_cache_free(fctl_job_cache
, (void *)job
);
4327 fctl_enque_job(fc_local_port_t
*port
, job_request_t
*job
)
4329 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
4331 mutex_enter(&port
->fp_mutex
);
4333 if (port
->fp_job_tail
== NULL
) {
4334 ASSERT(port
->fp_job_head
== NULL
);
4335 port
->fp_job_head
= port
->fp_job_tail
= job
;
4337 port
->fp_job_tail
->job_next
= job
;
4338 port
->fp_job_tail
= job
;
4340 job
->job_next
= NULL
;
4342 cv_signal(&port
->fp_cv
);
4343 mutex_exit(&port
->fp_mutex
);
4348 fctl_deque_job(fc_local_port_t
*port
)
4352 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
4354 if (port
->fp_job_head
== NULL
) {
4355 ASSERT(port
->fp_job_tail
== NULL
);
4358 job
= port
->fp_job_head
;
4359 if (job
->job_next
== NULL
) {
4360 ASSERT(job
== port
->fp_job_tail
);
4361 port
->fp_job_tail
= NULL
;
4363 port
->fp_job_head
= job
->job_next
;
4371 fctl_priority_enque_job(fc_local_port_t
*port
, job_request_t
*job
)
4373 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
4375 mutex_enter(&port
->fp_mutex
);
4376 if (port
->fp_job_tail
== NULL
) {
4377 ASSERT(port
->fp_job_head
== NULL
);
4378 port
->fp_job_head
= port
->fp_job_tail
= job
;
4379 job
->job_next
= NULL
;
4381 job
->job_next
= port
->fp_job_head
;
4382 port
->fp_job_head
= job
;
4384 cv_signal(&port
->fp_cv
);
4385 mutex_exit(&port
->fp_mutex
);
4390 fctl_jobwait(job_request_t
*job
)
4392 ASSERT(!(job
->job_flags
& JOB_TYPE_FCTL_ASYNC
));
4393 sema_p(&job
->job_fctl_sema
);
4394 ASSERT(!MUTEX_HELD(&job
->job_mutex
));
4399 fctl_jobdone(job_request_t
*job
)
4401 if (job
->job_flags
& JOB_TYPE_FCTL_ASYNC
) {
4402 if (job
->job_comp
) {
4403 job
->job_comp(job
->job_cb_arg
, job
->job_result
);
4405 fctl_dealloc_job(job
);
4407 sema_v(&job
->job_fctl_sema
);
4414 * The NAA can't be omitted for comparison.
4417 * if src == dst return 0
4418 * if src > dst return 1
4419 * if src < dst return -1
4422 fctl_wwn_cmp(la_wwn_t
*src
, la_wwn_t
*dst
)
4431 for (i
= 0, wl
= 0; i
< 8; i
++) {
4435 for (i
= 0, wr
= 0; i
< 8; i
++) {
4442 } else if (wl
== wr
) {
4451 * ASCII to Integer goodie with support for base 16, 10, 2 and 8
4454 fctl_atoi(char *s
, int base
)
4459 for (val
= 0; *s
!= '\0'; s
++) {
4462 if (*s
>= '0' && *s
<= '9') {
4464 } else if (*s
>= 'a' && *s
<= 'f') {
4466 } else if (*s
>= 'A' && *s
<= 'F') {
4474 if (*s
< '0' || *s
> '9') {
4481 if (*s
< '0' || *s
> '1') {
4488 if (*s
< '0' || *s
> '7') {
4497 val
= (val
* base
) + ch
;
4504 * Create the fc_remote_port_t struct for the given port_wwn and d_id.
4506 * If the struct already exists (and is "valid"), then use it. Before using
4507 * it, the code below also checks: (a) if the d_id has changed, and (b) if
4508 * the device is maked as PORT_DEVICE_OLD.
4510 * If no fc_remote_node_t struct exists for the given node_wwn, then that
4511 * struct is also created (and linked with the fc_remote_port_t).
4513 * The given fc_local_port_t struct is updated with the info on the new
4514 * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
4515 * The global node_hash_table[] is updated (if necessary).
4518 fctl_create_remote_port(fc_local_port_t
*port
, la_wwn_t
*node_wwn
,
4519 la_wwn_t
*port_wwn
, uint32_t d_id
, uchar_t recepient
, int sleep
)
4522 fc_remote_node_t
*rnodep
;
4523 fc_remote_port_t
*pd
;
4525 rnodep
= fctl_get_remote_node_by_nwwn(node_wwn
);
4528 * We found an fc_remote_node_t for the remote node -- see if
4529 * anyone has marked it as going away or gone.
4531 mutex_enter(&rnodep
->fd_mutex
);
4532 invalid
= (rnodep
->fd_flags
== FC_REMOTE_NODE_INVALID
) ? 1 : 0;
4533 mutex_exit(&rnodep
->fd_mutex
);
4535 if (rnodep
== NULL
|| invalid
) {
4537 * No valid remote node struct found -- create it.
4538 * Note: this is the only place that this func is called.
4540 rnodep
= fctl_create_remote_node(node_wwn
, sleep
);
4541 if (rnodep
== NULL
) {
4546 mutex_enter(&port
->fp_mutex
);
4549 * See if there already is an fc_remote_port_t struct in existence
4550 * on the specified fc_local_port_t for the given pwwn. If so, then
4551 * grab a reference to it. The 'held' here just means that fp_mutex
4552 * is held by the caller -- no reference counts are updated.
4554 pd
= fctl_get_remote_port_by_pwwn_mutex_held(port
, port_wwn
);
4557 * An fc_remote_port_t struct was found -- see if anyone has
4558 * marked it as "invalid", which means that it is in the
4559 * process of going away & we don't want to use it.
4561 mutex_enter(&pd
->pd_mutex
);
4562 invalid
= (pd
->pd_state
== PORT_DEVICE_INVALID
) ? 1 : 0;
4563 mutex_exit(&pd
->pd_mutex
);
4566 if (pd
== NULL
|| invalid
) {
4568 * No fc_remote_port_t was found (or the existing one is
4569 * marked as "invalid".) Allocate a new one and use that.
4570 * This call will also update the d_id and pwwn hash tables
4571 * in the given fc_local_port_t struct with the newly allocated
4574 if ((pd
= fctl_alloc_remote_port(port
, port_wwn
, d_id
,
4575 recepient
, sleep
)) == NULL
) {
4576 /* Just give up if the allocation fails. */
4577 mutex_exit(&port
->fp_mutex
);
4578 fctl_destroy_remote_node(rnodep
);
4583 * Add the new fc_remote_port_t struct to the d_id and pwwn
4584 * hash tables on the associated fc_local_port_t struct.
4586 mutex_enter(&pd
->pd_mutex
);
4587 pd
->pd_remote_nodep
= rnodep
;
4588 fctl_enlist_did_table(port
, pd
);
4589 fctl_enlist_pwwn_table(port
, pd
);
4590 mutex_exit(&pd
->pd_mutex
);
4591 mutex_exit(&port
->fp_mutex
);
4594 * Retrieve a pointer to the fc_remote_node_t (i.e., remote
4595 * node) specified by the given node_wwn. This looks in the
4596 * global fctl_nwwn_hash_table[]. The fd_numports reference
4597 * count in the fc_remote_node_t struct is incremented.
4599 rnodep
= fctl_lock_remote_node_by_nwwn(node_wwn
);
4603 * An existing and valid fc_remote_port_t struct already
4604 * exists on the fc_local_port_t for the given pwwn.
4607 mutex_enter(&pd
->pd_mutex
);
4608 ASSERT(pd
->pd_remote_nodep
!= NULL
);
4610 if (pd
->pd_port_id
.port_id
!= d_id
) {
4612 * A very unlikely occurance in a well
4613 * behaved environment.
4617 * The existing fc_remote_port_t has a different
4618 * d_id than what we were given. This code will
4619 * update the existing one with the one that was
4622 char string
[(FCTL_WWN_SIZE(port_wwn
) << 1) + 1];
4625 fc_wwn_to_str(port_wwn
, string
);
4627 old_id
= pd
->pd_port_id
.port_id
;
4629 fctl_delist_did_table(port
, pd
);
4631 cmn_err(CE_NOTE
, "!fctl(%d): D_ID of a device"
4632 " with PWWN %s changed. New D_ID = %x,"
4633 " OLD D_ID = %x", port
->fp_instance
, string
,
4636 pd
->pd_port_id
.port_id
= d_id
;
4639 * Looks like we have to presume here that the
4640 * remote port could be something entirely different
4641 * from what was previously existing & valid at this
4644 pd
->pd_type
= PORT_DEVICE_CHANGED
;
4646 /* Record (update) the new d_id for the remote port */
4647 fctl_enlist_did_table(port
, pd
);
4649 } else if (pd
->pd_type
== PORT_DEVICE_OLD
) {
4651 * OK at least the old & new d_id's match. So for
4652 * PORT_DEVICE_OLD, this assumes that the remote
4653 * port had disappeared but now has come back.
4654 * Update the pd_type and pd_state to put the
4655 * remote port back into service.
4657 pd
->pd_type
= PORT_DEVICE_NOCHANGE
;
4658 pd
->pd_state
= PORT_DEVICE_VALID
;
4660 fctl_enlist_did_table(port
, pd
);
4664 * OK the old & new d_id's match, and the remote
4665 * port struct is not marked as PORT_DEVICE_OLD, so
4666 * presume that it's still the same device and is
4667 * still in good shape. Also this presumes that we
4668 * do not need to update d_id or pwwn hash tables.
4670 /* sanitize device values */
4671 pd
->pd_type
= PORT_DEVICE_NOCHANGE
;
4672 pd
->pd_state
= PORT_DEVICE_VALID
;
4675 mutex_exit(&pd
->pd_mutex
);
4676 mutex_exit(&port
->fp_mutex
);
4678 if (rnodep
!= pd
->pd_remote_nodep
) {
4679 if ((rnodep
!= NULL
) &&
4680 (fctl_wwn_cmp(&pd
->pd_remote_nodep
->fd_node_name
,
4683 * Rut-roh, there is an fc_remote_node_t remote
4684 * node struct for the given node_wwn, but the
4685 * fc_remote_port_t remote port struct doesn't
4686 * know about it. This just prints a warning
4687 * message & fails the fc_remote_port_t
4688 * allocation (possible leak here?).
4694 &pd
->pd_remote_nodep
->fd_node_name
,
4696 fc_wwn_to_str(node_wwn
, ww2_name
);
4698 cmn_err(CE_WARN
, "fctl(%d) NWWN Mismatch: "
4699 "Expected %s Got %s", port
->fp_instance
,
4700 ww1_name
, ww2_name
);
4708 * Add the fc_remote_port_t onto the linked list of remote port
4709 * devices associated with the given fc_remote_node_t (remote node).
4711 fctl_link_remote_port_to_remote_node(rnodep
, pd
);
4718 * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
4719 * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
4720 * references to the fc_remote_port_t from the d_id and pwwn tables in the
4721 * given fc_local_port_t. Deallocates the given fc_remote_port_t.
4723 * Returns a count of the number of remaining fc_remote_port_t structs
4724 * associated with the fc_remote_node_t struct.
4726 * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
4727 * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
4728 * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
4729 * the cleanup. The function then also returns '1'
4730 * instead of the actual number of remaining fc_remote_port_t structs
4732 * If there are no more remote ports on the remote node, return 0.
4733 * Otherwise, return non-zero.
4736 fctl_destroy_remote_port(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
4738 fc_remote_node_t
*rnodep
;
4741 mutex_enter(&pd
->pd_mutex
);
4744 * If pd_ref_count > 0, we can't pull the rug out from any
4745 * current users of this fc_remote_port_t. We'll mark it as old
4746 * and in need of removal. The same goes for any fc_remote_port_t
4747 * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
4748 * have not yet been notified that the handle is no longer valid
4749 * (i.e., PD_GIVEN_TO_ULPS is set).
4751 if ((pd
->pd_ref_count
> 0) ||
4752 (pd
->pd_aux_flags
& PD_GIVEN_TO_ULPS
)) {
4753 pd
->pd_aux_flags
|= PD_NEEDS_REMOVAL
;
4754 pd
->pd_type
= PORT_DEVICE_OLD
;
4755 mutex_exit(&pd
->pd_mutex
);
4759 pd
->pd_type
= PORT_DEVICE_OLD
;
4761 rnodep
= pd
->pd_remote_nodep
;
4763 mutex_exit(&pd
->pd_mutex
);
4765 if (rnodep
!= NULL
) {
4767 * Remove the fc_remote_port_t from the linked list of remote
4768 * ports for the given fc_remote_node_t. This is only called
4769 * here and in fctl_destroy_all_remote_ports().
4771 rcount
= fctl_unlink_remote_port_from_remote_node(rnodep
, pd
);
4774 mutex_enter(&port
->fp_mutex
);
4775 mutex_enter(&pd
->pd_mutex
);
4777 fctl_delist_did_table(port
, pd
);
4778 fctl_delist_pwwn_table(port
, pd
);
4780 mutex_exit(&pd
->pd_mutex
);
4783 * Deconstruct & free the fc_remote_port_t. This is only called
4784 * here and in fctl_destroy_all_remote_ports().
4786 fctl_dealloc_remote_port(pd
);
4788 mutex_exit(&port
->fp_mutex
);
4795 * This goes thru the d_id table on the given fc_local_port_t.
4796 * For each fc_remote_port_t found, this will:
4798 * - Remove the fc_remote_port_t from the linked list of remote ports for
4799 * the associated fc_remote_node_t. If the linked list goes empty, then this
4800 * tries to deconstruct & free the fc_remote_node_t (that also removes the
4801 * fc_remote_node_t from the global fctl_nwwn_hash_table[]).
4803 * - Remove the fc_remote_port_t from the pwwn list on the given
4806 * - Deconstruct and free the fc_remote_port_t.
4808 * - Removes the link to the fc_remote_port_t in the d_id table. Note, this
4809 * does not appear to correctle decrement the d_id_count tho.
4812 fctl_destroy_all_remote_ports(fc_local_port_t
*port
)
4815 fc_remote_port_t
*pd
;
4816 fc_remote_node_t
*rnodep
;
4817 struct d_id_hash
*head
;
4819 mutex_enter(&port
->fp_mutex
);
4821 for (index
= 0; index
< did_table_size
; index
++) {
4823 head
= &port
->fp_did_table
[index
];
4825 while (head
->d_id_head
!= NULL
) {
4826 pd
= head
->d_id_head
;
4829 * See if this remote port (fc_remote_port_t) has a
4830 * reference to a remote node (fc_remote_node_t) in its
4831 * pd->pd_remote_nodep pointer.
4833 mutex_enter(&pd
->pd_mutex
);
4834 rnodep
= pd
->pd_remote_nodep
;
4835 mutex_exit(&pd
->pd_mutex
);
4837 if (rnodep
!= NULL
) {
4839 * An fc_remote_node_t reference exists. Remove
4840 * the fc_remote_port_t from the linked list of
4841 * remote ports for fc_remote_node_t.
4843 if (fctl_unlink_remote_port_from_remote_node(
4846 * The fd_numports reference count
4847 * in the fc_remote_node_t has come
4848 * back as zero, so we can free the
4849 * fc_remote_node_t. This also means
4850 * that the fc_remote_node_t was
4852 * fctl_nwwn_hash_table[].
4854 * This will silently skip the
4855 * kmem_free() if either the
4856 * fd_numports is nonzero or
4857 * the fd_port is not NULL in
4858 * the fc_remote_node_t.
4860 fctl_destroy_remote_node(rnodep
);
4865 * Clean up the entry in the fc_local_port_t's pwwn
4866 * table for the given fc_remote_port_t (i.e., the pd).
4868 mutex_enter(&pd
->pd_mutex
);
4869 fctl_delist_pwwn_table(port
, pd
);
4870 pd
->pd_aux_flags
&= ~PD_IN_DID_QUEUE
;
4871 mutex_exit(&pd
->pd_mutex
);
4874 * Remove the current entry from the d_id list.
4876 head
->d_id_head
= pd
->pd_did_hnext
;
4879 * Deconstruct & free the fc_remote_port_t (pd)
4880 * Note: this is only called here and in
4881 * fctl_destroy_remote_port_t().
4883 fctl_dealloc_remote_port(pd
);
4887 mutex_exit(&port
->fp_mutex
);
4892 fctl_is_wwn_zero(la_wwn_t
*wwn
)
4896 for (count
= 0; count
< sizeof (la_wwn_t
); count
++) {
4897 if (wwn
->raw_wwn
[count
] != 0) {
4898 return (FC_FAILURE
);
4902 return (FC_SUCCESS
);
4907 fctl_ulp_unsol_cb(fc_local_port_t
*port
, fc_unsol_buf_t
*buf
, uchar_t type
)
4913 fc_ulp_module_t
*mod
;
4914 fc_ulp_ports_t
*ulp_port
;
4919 switch ((buf
->ub_frame
.r_ctl
) & R_CTL_ROUTING
) {
4920 case R_CTL_DEVICE_DATA
:
4924 case R_CTL_EXTENDED_SVC
:
4933 mutex_enter(&port
->fp_mutex
);
4934 ASSERT(port
->fp_active_ubs
> 0);
4935 if (--(port
->fp_active_ubs
) == 0) {
4936 port
->fp_soft_state
&= ~FP_SOFT_IN_UNSOL_CB
;
4938 mutex_exit(&port
->fp_mutex
);
4939 port
->fp_fca_tran
->fca_ub_release(port
->fp_fca_handle
,
4944 rw_enter(&fctl_ulp_lock
, RW_READER
);
4945 for (mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
4946 if (check_type
&& mod
->mod_info
->ulp_type
!= type
) {
4950 rw_enter(&fctl_mod_ports_lock
, RW_READER
);
4951 ulp_port
= fctl_get_ulp_port(mod
, port
);
4952 rw_exit(&fctl_mod_ports_lock
);
4954 if (ulp_port
== NULL
) {
4958 mutex_enter(&ulp_port
->port_mutex
);
4959 if (FCTL_DISALLOW_CALLBACKS(ulp_port
->port_dstate
)) {
4960 mutex_exit(&ulp_port
->port_mutex
);
4963 mutex_exit(&ulp_port
->port_mutex
);
4966 rval
= mod
->mod_info
->ulp_data_callback(
4967 mod
->mod_info
->ulp_handle
,
4968 (opaque_t
)port
, buf
, claimed
);
4970 rval
= mod
->mod_info
->ulp_els_callback(
4971 mod
->mod_info
->ulp_handle
,
4972 (opaque_t
)port
, buf
, claimed
);
4975 if (rval
== FC_SUCCESS
&& claimed
== 0) {
4979 rw_exit(&fctl_ulp_lock
);
4983 * We should actually RJT since nobody claimed it.
4985 mutex_enter(&port
->fp_mutex
);
4986 ASSERT(port
->fp_active_ubs
> 0);
4987 if (--(port
->fp_active_ubs
) == 0) {
4988 port
->fp_soft_state
&= ~FP_SOFT_IN_UNSOL_CB
;
4990 mutex_exit(&port
->fp_mutex
);
4991 port
->fp_fca_tran
->fca_ub_release(port
->fp_fca_handle
,
4995 mutex_enter(&port
->fp_mutex
);
4996 if (--port
->fp_active_ubs
== 0) {
4997 port
->fp_soft_state
&= ~FP_SOFT_IN_UNSOL_CB
;
4999 mutex_exit(&port
->fp_mutex
);
5005 * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
5007 * With all these mutexes held, we should make sure this function does not eat
5011 fctl_copy_portmap_held(fc_portmap_t
*map
, fc_remote_port_t
*pd
)
5013 fc_remote_node_t
*node
;
5015 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
5017 map
->map_pwwn
= pd
->pd_port_name
;
5018 map
->map_did
= pd
->pd_port_id
;
5019 map
->map_hard_addr
= pd
->pd_hard_addr
;
5020 map
->map_state
= pd
->pd_state
;
5021 map
->map_type
= pd
->pd_type
;
5024 ASSERT(map
->map_type
<= PORT_DEVICE_DELETE
);
5026 bcopy(pd
->pd_fc4types
, map
->map_fc4_types
, sizeof (pd
->pd_fc4types
));
5028 node
= pd
->pd_remote_nodep
;
5030 ASSERT(MUTEX_HELD(&node
->fd_mutex
));
5033 map
->map_nwwn
= node
->fd_node_name
;
5039 fctl_copy_portmap(fc_portmap_t
*map
, fc_remote_port_t
*pd
)
5041 fc_remote_node_t
*node
;
5043 ASSERT(!MUTEX_HELD(&pd
->pd_mutex
));
5045 mutex_enter(&pd
->pd_mutex
);
5046 map
->map_pwwn
= pd
->pd_port_name
;
5047 map
->map_did
= pd
->pd_port_id
;
5048 map
->map_hard_addr
= pd
->pd_hard_addr
;
5049 map
->map_state
= pd
->pd_state
;
5050 map
->map_type
= pd
->pd_type
;
5053 ASSERT(map
->map_type
<= PORT_DEVICE_DELETE
);
5055 bcopy(pd
->pd_fc4types
, map
->map_fc4_types
, sizeof (pd
->pd_fc4types
));
5057 node
= pd
->pd_remote_nodep
;
5058 mutex_exit(&pd
->pd_mutex
);
5061 mutex_enter(&node
->fd_mutex
);
5062 map
->map_nwwn
= node
->fd_node_name
;
5063 mutex_exit(&node
->fd_mutex
);
5070 fctl_update_host_ns_values(fc_local_port_t
*port
, fc_ns_cmd_t
*ns_req
)
5072 int rval
= FC_SUCCESS
;
5074 switch (ns_req
->ns_cmd
) {
5081 rfc
= (ns_rfc_type_t
*)ns_req
->ns_req_payload
;
5083 mutex_enter(&port
->fp_mutex
);
5084 src
= (uint32_t *)port
->fp_fc4_types
;
5085 dst
= (uint32_t *)rfc
->rfc_types
;
5087 for (count
= 0; count
< 8; count
++) {
5090 mutex_exit(&port
->fp_mutex
);
5098 spn
= (ns_spn_t
*)ns_req
->ns_req_payload
;
5100 mutex_enter(&port
->fp_mutex
);
5101 port
->fp_sym_port_namelen
= spn
->spn_len
;
5103 bcopy((caddr_t
)spn
+ sizeof (ns_spn_t
),
5104 port
->fp_sym_port_name
, spn
->spn_len
);
5106 mutex_exit(&port
->fp_mutex
);
5114 snn
= (ns_snn_t
*)ns_req
->ns_req_payload
;
5116 mutex_enter(&port
->fp_mutex
);
5117 port
->fp_sym_node_namelen
= snn
->snn_len
;
5119 bcopy((caddr_t
)snn
+ sizeof (ns_snn_t
),
5120 port
->fp_sym_node_name
, snn
->snn_len
);
5122 mutex_exit(&port
->fp_mutex
);
5130 rip
= (ns_rip_t
*)ns_req
->ns_req_payload
;
5132 mutex_enter(&port
->fp_mutex
);
5133 bcopy(rip
->rip_ip_addr
, port
->fp_ip_addr
,
5134 sizeof (rip
->rip_ip_addr
));
5135 mutex_exit(&port
->fp_mutex
);
5143 ipa
= (ns_ipa_t
*)ns_req
->ns_req_payload
;
5145 mutex_enter(&port
->fp_mutex
);
5146 bcopy(ipa
->ipa_value
, port
->fp_ipa
, sizeof (ipa
->ipa_value
));
5147 mutex_exit(&port
->fp_mutex
);
5153 rval
= FC_BADOBJECT
;
5162 fctl_retrieve_host_ns_values(fc_local_port_t
*port
, fc_ns_cmd_t
*ns_req
)
5164 int rval
= FC_SUCCESS
;
5166 switch (ns_req
->ns_cmd
) {
5170 rfc
= (ns_rfc_type_t
*)ns_req
->ns_resp_payload
;
5172 mutex_enter(&port
->fp_mutex
);
5173 bcopy(port
->fp_fc4_types
, rfc
->rfc_types
,
5174 sizeof (rfc
->rfc_types
));
5175 mutex_exit(&port
->fp_mutex
);
5182 spn
= (ns_spn_t
*)ns_req
->ns_resp_payload
;
5184 mutex_enter(&port
->fp_mutex
);
5185 spn
->spn_len
= port
->fp_sym_port_namelen
;
5187 bcopy(port
->fp_sym_port_name
, (caddr_t
)spn
+
5188 sizeof (ns_spn_t
), spn
->spn_len
);
5190 mutex_exit(&port
->fp_mutex
);
5198 snn
= (ns_snn_t
*)ns_req
->ns_resp_payload
;
5200 mutex_enter(&port
->fp_mutex
);
5201 snn
->snn_len
= port
->fp_sym_node_namelen
;
5203 bcopy(port
->fp_sym_node_name
, (caddr_t
)snn
+
5204 sizeof (ns_snn_t
), snn
->snn_len
);
5206 mutex_exit(&port
->fp_mutex
);
5214 rip
= (ns_rip_t
*)ns_req
->ns_resp_payload
;
5216 mutex_enter(&port
->fp_mutex
);
5217 bcopy(port
->fp_ip_addr
, rip
->rip_ip_addr
,
5218 sizeof (rip
->rip_ip_addr
));
5219 mutex_exit(&port
->fp_mutex
);
5227 ipa
= (ns_ipa_t
*)ns_req
->ns_resp_payload
;
5229 mutex_enter(&port
->fp_mutex
);
5230 bcopy(port
->fp_ipa
, ipa
->ipa_value
, sizeof (ipa
->ipa_value
));
5231 mutex_exit(&port
->fp_mutex
);
5237 rval
= FC_BADOBJECT
;
5246 fctl_alloc_ns_cmd(uint32_t cmd_len
, uint32_t resp_len
, uint32_t data_len
,
5247 uint32_t ns_flags
, int sleep
)
5249 fctl_ns_req_t
*ns_cmd
;
5251 ns_cmd
= kmem_zalloc(sizeof (*ns_cmd
), sleep
);
5252 if (ns_cmd
== NULL
) {
5257 ns_cmd
->ns_cmd_buf
= kmem_zalloc(cmd_len
, sleep
);
5258 if (ns_cmd
->ns_cmd_buf
== NULL
) {
5259 kmem_free(ns_cmd
, sizeof (*ns_cmd
));
5262 ns_cmd
->ns_cmd_size
= cmd_len
;
5265 ns_cmd
->ns_resp_size
= resp_len
;
5268 ns_cmd
->ns_data_buf
= kmem_zalloc(data_len
, sleep
);
5269 if (ns_cmd
->ns_data_buf
== NULL
) {
5270 if (ns_cmd
->ns_cmd_buf
&& cmd_len
) {
5271 kmem_free(ns_cmd
->ns_cmd_buf
, cmd_len
);
5273 kmem_free(ns_cmd
, sizeof (*ns_cmd
));
5276 ns_cmd
->ns_data_len
= data_len
;
5278 ns_cmd
->ns_flags
= ns_flags
;
5285 fctl_free_ns_cmd(fctl_ns_req_t
*ns_cmd
)
5287 if (ns_cmd
->ns_cmd_size
&& ns_cmd
->ns_cmd_buf
) {
5288 kmem_free(ns_cmd
->ns_cmd_buf
, ns_cmd
->ns_cmd_size
);
5290 if (ns_cmd
->ns_data_len
&& ns_cmd
->ns_data_buf
) {
5291 kmem_free(ns_cmd
->ns_data_buf
, ns_cmd
->ns_data_len
);
5293 kmem_free(ns_cmd
, sizeof (*ns_cmd
));
5298 fctl_ulp_port_ioctl(fc_local_port_t
*port
, dev_t dev
, int cmd
,
5299 intptr_t data
, int mode
, cred_t
*credp
, int *rval
)
5304 fc_ulp_module_t
*mod
;
5305 fc_ulp_ports_t
*ulp_port
;
5310 rw_enter(&fctl_ulp_lock
, RW_READER
);
5311 for (claimed
= 0, mod
= fctl_ulp_modules
; mod
; mod
= mod
->mod_next
) {
5312 rw_enter(&fctl_mod_ports_lock
, RW_READER
);
5313 ulp_port
= fctl_get_ulp_port(mod
, port
);
5314 rw_exit(&fctl_mod_ports_lock
);
5316 if (ulp_port
== NULL
) {
5320 mutex_enter(&ulp_port
->port_mutex
);
5321 if (FCTL_DISALLOW_CALLBACKS(ulp_port
->port_dstate
) ||
5322 mod
->mod_info
->ulp_port_ioctl
== NULL
) {
5323 mutex_exit(&ulp_port
->port_mutex
);
5326 mutex_exit(&ulp_port
->port_mutex
);
5328 ret
= mod
->mod_info
->ulp_port_ioctl(
5329 mod
->mod_info
->ulp_handle
, (opaque_t
)port
,
5330 dev
, cmd
, data
, mode
, credp
, rval
, claimed
);
5332 if (ret
== FC_SUCCESS
&& claimed
== 0) {
5336 rw_exit(&fctl_ulp_lock
);
5345 * raise power if necessary, and set the port busy
5347 * this may cause power to be raised, so no power related locks should
5351 fc_ulp_busy_port(opaque_t port_handle
)
5353 fc_local_port_t
*port
= port_handle
;
5355 return (fctl_busy_port(port
));
5359 fc_ulp_idle_port(opaque_t port_handle
)
5361 fc_local_port_t
*port
= port_handle
;
5362 fctl_idle_port(port
);
5366 fc_ulp_copy_portmap(fc_portmap_t
*map
, opaque_t pd
)
5368 fctl_copy_portmap(map
, (fc_remote_port_t
*)pd
);
5373 fc_ulp_get_npiv_port_num(opaque_t port_handle
)
5376 fc_local_port_t
*port
= port_handle
;
5377 fc_local_port_t
*tmpport
;
5379 mutex_enter(&port
->fp_mutex
);
5380 tmpport
= port
->fp_port_next
;
5382 mutex_exit(&port
->fp_mutex
);
5385 while (tmpport
!= port
) {
5387 tmpport
= tmpport
->fp_port_next
;
5389 mutex_exit(&port
->fp_mutex
);
5394 fc_get_npiv_port(fc_local_port_t
*phyport
, la_wwn_t
*pwwn
)
5396 fc_fca_port_t
*fca_port
;
5397 fc_local_port_t
*tmpPort
= phyport
;
5399 mutex_enter(&fctl_port_lock
);
5401 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
5402 fca_port
= fca_port
->port_next
) {
5403 tmpPort
= fca_port
->port_handle
;
5404 if (tmpPort
== NULL
) {
5407 mutex_enter(&tmpPort
->fp_mutex
);
5408 if (bcmp(tmpPort
->fp_service_params
.nport_ww_name
.raw_wwn
,
5409 pwwn
->raw_wwn
, sizeof (la_wwn_t
)) == 0) {
5410 mutex_exit(&tmpPort
->fp_mutex
);
5411 mutex_exit(&fctl_port_lock
);
5414 mutex_exit(&tmpPort
->fp_mutex
);
5417 mutex_exit(&fctl_port_lock
);
5423 fc_ulp_get_npiv_port_list(opaque_t port_handle
, char *pathList
)
5426 fc_local_port_t
*port
= port_handle
;
5427 fc_local_port_t
*tmpport
;
5429 mutex_enter(&port
->fp_mutex
);
5430 tmpport
= port
->fp_port_next
;
5431 if (!tmpport
|| (port
->fp_npiv_type
== FC_NPIV_PORT
)) {
5432 mutex_exit(&port
->fp_mutex
);
5436 while (tmpport
!= port
) {
5437 (void) ddi_pathname(tmpport
->fp_port_dip
,
5438 &pathList
[MAXPATHLEN
* portsnum
]);
5440 tmpport
= tmpport
->fp_port_next
;
5442 mutex_exit(&port
->fp_mutex
);
5449 fc_delete_npiv_port(fc_local_port_t
*port
, la_wwn_t
*pwwn
)
5451 fc_local_port_t
*tmpport
;
5453 mutex_enter(&port
->fp_mutex
);
5454 tmpport
= port
->fp_port_next
;
5455 if (!tmpport
|| (port
->fp_npiv_type
== FC_NPIV_PORT
)) {
5456 mutex_exit(&port
->fp_mutex
);
5460 while (tmpport
!= port
) {
5461 if ((bcmp(tmpport
->fp_service_params
.nport_ww_name
.raw_wwn
,
5462 pwwn
->raw_wwn
, sizeof (la_wwn_t
)) == 0) &&
5463 (tmpport
->fp_npiv_state
== 0)) {
5464 tmpport
->fp_npiv_state
= FC_NPIV_DELETING
;
5465 mutex_exit(&port
->fp_mutex
);
5468 tmpport
= tmpport
->fp_port_next
;
5471 mutex_exit(&port
->fp_mutex
);
5476 * Get the list of Adapters. On multi-ported adapters,
5477 * only ONE port on the adapter will be returned.
5478 * pathList should be (count * MAXPATHLEN) long.
5479 * The return value will be set to the number of
5480 * HBAs that were found on the system. If the value
5481 * is greater than count, the routine should be retried
5482 * with a larger buffer.
5485 fc_ulp_get_adapter_paths(char *pathList
, int count
)
5487 fc_fca_port_t
*fca_port
;
5488 int in
= 0, out
= 0, check
, skip
, maxPorts
= 0;
5489 fc_local_port_t
**portList
;
5490 fc_local_port_t
*new_port
, *stored_port
;
5491 fca_hba_fru_details_t
*new_fru
, *stored_fru
;
5493 ASSERT(pathList
!= NULL
);
5495 /* First figure out how many ports we have */
5496 mutex_enter(&fctl_port_lock
);
5498 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
5499 fca_port
= fca_port
->port_next
) {
5503 /* Now allocate a buffer to store all the pointers for comparisons */
5504 portList
= kmem_zalloc(sizeof (fc_local_port_t
*) * maxPorts
, KM_SLEEP
);
5506 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
5507 fca_port
= fca_port
->port_next
) {
5510 /* Lock the new port for subsequent comparisons */
5511 new_port
= fca_port
->port_handle
;
5512 mutex_enter(&new_port
->fp_mutex
);
5513 new_fru
= &new_port
->fp_hba_port_attrs
.hba_fru_details
;
5515 /* Filter out secondary ports from the list */
5516 for (check
= 0; check
< out
; check
++) {
5517 if (portList
[check
] == NULL
) {
5520 /* Guard against duplicates (should never happen) */
5521 if (portList
[check
] == fca_port
->port_handle
) {
5527 /* Lock the already stored port for comparison */
5528 stored_port
= portList
[check
];
5529 mutex_enter(&stored_port
->fp_mutex
);
5531 &stored_port
->fp_hba_port_attrs
.hba_fru_details
;
5533 /* Are these ports on the same HBA? */
5534 if (new_fru
->high
== stored_fru
->high
&&
5535 new_fru
->low
== stored_fru
->low
) {
5536 /* Now double check driver */
5538 new_port
->fp_hba_port_attrs
.driver_name
,
5539 stored_port
->fp_hba_port_attrs
.driver_name
,
5540 FCHBA_DRIVER_NAME_LEN
) == 0) {
5541 /* we don't need to grow the list */
5543 /* looking at a lower port index? */
5544 if (new_fru
->port_index
<
5545 stored_fru
->port_index
) {
5546 /* Replace the port in list */
5548 &stored_port
->fp_mutex
);
5549 if (new_port
->fp_npiv_type
==
5553 portList
[check
] = new_port
;
5555 } /* Else, just skip this port */
5559 mutex_exit(&stored_port
->fp_mutex
);
5561 mutex_exit(&new_port
->fp_mutex
);
5565 * Either this is the first port for this HBA, or
5566 * it's a secondary port and we haven't stored the
5567 * primary/first port for that HBA. In the latter case,
5568 * will just filter it out as we proceed to loop.
5570 if (fca_port
->port_handle
->fp_npiv_type
==
5574 portList
[out
++] = fca_port
->port_handle
;
5580 for (in
= 0; in
< out
; in
++) {
5581 (void) ddi_pathname(portList
[in
]->fp_port_dip
,
5582 &pathList
[MAXPATHLEN
* in
]);
5585 mutex_exit(&fctl_port_lock
);
5586 kmem_free(portList
, sizeof (*portList
) * maxPorts
);
5591 fc_ulp_get_rscn_count(opaque_t port_handle
)
5594 fc_local_port_t
*port
;
5596 port
= (fc_local_port_t
*)port_handle
;
5597 mutex_enter(&port
->fp_mutex
);
5598 count
= port
->fp_rscn_count
;
5599 mutex_exit(&port
->fp_mutex
);
5606 * This function is a very similar to fctl_add_orphan except that it expects
5607 * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
5609 * Note that there is a lock hierarchy here (fp_mutex should be held first) but
5610 * since this function could be called with a different pd's pd_mutex held, we
5611 * should take care not to release fp_mutex in this function.
5614 fctl_add_orphan_held(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
5616 int rval
= FC_FAILURE
;
5619 fc_orphan_t
*orphan
;
5621 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
5622 ASSERT(MUTEX_HELD(&pd
->pd_mutex
));
5624 pwwn
= pd
->pd_port_name
;
5626 for (orp
= port
->fp_orphan_list
; orp
!= NULL
; orp
= orp
->orp_next
) {
5627 if (fctl_wwn_cmp(&orp
->orp_pwwn
, &pwwn
) == 0) {
5628 return (FC_SUCCESS
);
5632 orphan
= kmem_zalloc(sizeof (*orphan
), KM_NOSLEEP
);
5634 orphan
->orp_pwwn
= pwwn
;
5635 orphan
->orp_tstamp
= ddi_get_lbolt();
5637 if (port
->fp_orphan_list
) {
5638 ASSERT(port
->fp_orphan_count
> 0);
5639 orphan
->orp_next
= port
->fp_orphan_list
;
5641 port
->fp_orphan_list
= orphan
;
5642 port
->fp_orphan_count
++;
5651 fctl_add_orphan(fc_local_port_t
*port
, fc_remote_port_t
*pd
, int sleep
)
5653 int rval
= FC_FAILURE
;
5656 fc_orphan_t
*orphan
;
5658 mutex_enter(&port
->fp_mutex
);
5660 mutex_enter(&pd
->pd_mutex
);
5661 pwwn
= pd
->pd_port_name
;
5662 mutex_exit(&pd
->pd_mutex
);
5664 for (orp
= port
->fp_orphan_list
; orp
!= NULL
; orp
= orp
->orp_next
) {
5665 if (fctl_wwn_cmp(&orp
->orp_pwwn
, &pwwn
) == 0) {
5666 mutex_exit(&port
->fp_mutex
);
5667 return (FC_SUCCESS
);
5670 mutex_exit(&port
->fp_mutex
);
5672 orphan
= kmem_zalloc(sizeof (*orphan
), sleep
);
5673 if (orphan
!= NULL
) {
5674 mutex_enter(&port
->fp_mutex
);
5676 orphan
->orp_pwwn
= pwwn
;
5677 orphan
->orp_tstamp
= ddi_get_lbolt();
5679 if (port
->fp_orphan_list
) {
5680 ASSERT(port
->fp_orphan_count
> 0);
5681 orphan
->orp_next
= port
->fp_orphan_list
;
5683 port
->fp_orphan_list
= orphan
;
5684 port
->fp_orphan_count
++;
5685 mutex_exit(&port
->fp_mutex
);
5695 fctl_remove_if_orphan(fc_local_port_t
*port
, la_wwn_t
*pwwn
)
5697 int rval
= FC_FAILURE
;
5698 fc_orphan_t
*prev
= NULL
;
5701 mutex_enter(&port
->fp_mutex
);
5702 for (orp
= port
->fp_orphan_list
; orp
!= NULL
; orp
= orp
->orp_next
) {
5703 if (fctl_wwn_cmp(&orp
->orp_pwwn
, pwwn
) == 0) {
5705 prev
->orp_next
= orp
->orp_next
;
5707 ASSERT(port
->fp_orphan_list
== orp
);
5708 port
->fp_orphan_list
= orp
->orp_next
;
5710 port
->fp_orphan_count
--;
5716 mutex_exit(&port
->fp_mutex
);
5718 if (rval
== FC_SUCCESS
) {
5719 kmem_free(orp
, sizeof (*orp
));
5727 fctl_print_if_not_orphan(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
5733 mutex_enter(&port
->fp_mutex
);
5735 mutex_enter(&pd
->pd_mutex
);
5736 pwwn
= pd
->pd_port_name
;
5737 mutex_exit(&pd
->pd_mutex
);
5739 for (orp
= port
->fp_orphan_list
; orp
!= NULL
; orp
= orp
->orp_next
) {
5740 if (fctl_wwn_cmp(&orp
->orp_pwwn
, &pwwn
) == 0) {
5741 mutex_exit(&port
->fp_mutex
);
5745 mutex_exit(&port
->fp_mutex
);
5747 fc_wwn_to_str(&pwwn
, ww_name
);
5749 cmn_err(CE_WARN
, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
5750 " disappeared from fabric", port
->fp_instance
,
5751 pd
->pd_port_id
.port_id
, ww_name
);
5757 fctl_link_reset_done(opaque_t port_handle
, uchar_t result
)
5759 fc_local_port_t
*port
= port_handle
;
5761 mutex_enter(&port
->fp_mutex
);
5762 port
->fp_soft_state
&= ~FP_SOFT_IN_LINK_RESET
;
5763 mutex_exit(&port
->fp_mutex
);
5765 fctl_idle_port(port
);
5770 fctl_error(int fc_errno
, char **errmsg
)
5774 for (count
= 0; count
< sizeof (fc_errlist
) /
5775 sizeof (fc_errlist
[0]); count
++) {
5776 if (fc_errlist
[count
].fc_errno
== fc_errno
) {
5777 *errmsg
= fc_errlist
[count
].fc_errname
;
5778 return (FC_SUCCESS
);
5781 *errmsg
= fctl_undefined
;
5783 return (FC_FAILURE
);
5788 * Return number of successful translations.
5789 * Anybody with some userland programming experience would have
5790 * figured it by now that the return value exactly resembles that
5791 * of scanf(3c). This function returns a count of successful
5792 * translations. It could range from 0 (no match for state, reason,
5793 * action, expln) to 4 (successful matches for all state, reason,
5794 * action, expln) and where translation isn't successful into a
5795 * friendlier message the relevent field is set to "Undefined"
5798 fctl_pkt_error(fc_packet_t
*pkt
, char **state
, char **reason
,
5799 char **action
, char **expln
)
5804 fc_pkt_error_t
*error
;
5805 fc_pkt_reason_t
*reason_b
; /* Base pointer */
5806 fc_pkt_action_t
*action_b
; /* Base pointer */
5807 fc_pkt_expln_t
*expln_b
; /* Base pointer */
5810 *state
= *reason
= *action
= *expln
= fctl_undefined
;
5812 len
= sizeof (fc_pkt_errlist
) / sizeof fc_pkt_errlist
[0];
5813 for (index
= 0; index
< len
; index
++) {
5814 error
= fc_pkt_errlist
+ index
;
5815 if (pkt
->pkt_state
== error
->pkt_state
) {
5816 *state
= error
->pkt_msg
;
5819 reason_b
= error
->pkt_reason
;
5820 action_b
= error
->pkt_action
;
5821 expln_b
= error
->pkt_expln
;
5823 while (reason_b
!= NULL
&&
5824 reason_b
->reason_val
!= FC_REASON_INVALID
) {
5825 if (reason_b
->reason_val
== pkt
->pkt_reason
) {
5826 *reason
= reason_b
->reason_msg
;
5833 while (action_b
!= NULL
&&
5834 action_b
->action_val
!= FC_ACTION_INVALID
) {
5835 if (action_b
->action_val
== pkt
->pkt_action
) {
5836 *action
= action_b
->action_msg
;
5843 while (expln_b
!= NULL
&&
5844 expln_b
->expln_val
!= FC_EXPLN_INVALID
) {
5845 if (expln_b
->expln_val
== pkt
->pkt_expln
) {
5846 *expln
= expln_b
->expln_msg
;
5861 * Remove all port devices that are marked OLD, remove
5862 * corresponding node devices (fc_remote_node_t)
5865 fctl_remove_oldies(fc_local_port_t
*port
)
5869 fc_remote_node_t
*node
;
5870 struct pwwn_hash
*head
;
5871 fc_remote_port_t
*pd
;
5872 fc_remote_port_t
*old_pd
;
5873 fc_remote_port_t
*last_pd
;
5876 * Nuke all OLD devices
5878 mutex_enter(&port
->fp_mutex
);
5880 for (index
= 0; index
< pwwn_table_size
; index
++) {
5881 head
= &port
->fp_pwwn_table
[index
];
5883 pd
= head
->pwwn_head
;
5885 while (pd
!= NULL
) {
5886 mutex_enter(&pd
->pd_mutex
);
5887 if (pd
->pd_type
!= PORT_DEVICE_OLD
) {
5888 mutex_exit(&pd
->pd_mutex
);
5890 pd
= pd
->pd_wwn_hnext
;
5895 * Remove this from the PWWN hash table
5898 pd
= old_pd
->pd_wwn_hnext
;
5900 if (last_pd
== NULL
) {
5901 ASSERT(old_pd
== head
->pwwn_head
);
5902 head
->pwwn_head
= pd
;
5904 last_pd
->pd_wwn_hnext
= pd
;
5908 * Make sure we tie fp_dev_count to the size of the
5911 port
->fp_dev_count
--;
5912 old_pd
->pd_wwn_hnext
= NULL
;
5914 fctl_delist_did_table(port
, old_pd
);
5915 node
= old_pd
->pd_remote_nodep
;
5916 ASSERT(node
!= NULL
);
5918 initiator
= (old_pd
->pd_recepient
==
5919 PD_PLOGI_INITIATOR
) ? 1 : 0;
5921 mutex_exit(&old_pd
->pd_mutex
);
5923 if (FC_IS_TOP_SWITCH(port
->fp_topology
) && initiator
) {
5924 mutex_exit(&port
->fp_mutex
);
5926 (void) fctl_add_orphan(port
, old_pd
,
5929 mutex_exit(&port
->fp_mutex
);
5932 if (fctl_destroy_remote_port(port
, old_pd
) == 0) {
5934 fctl_destroy_remote_node(node
);
5938 mutex_enter(&port
->fp_mutex
);
5942 mutex_exit(&port
->fp_mutex
);
5947 fctl_check_alpa_list(fc_local_port_t
*port
, fc_remote_port_t
*pd
)
5949 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
5950 ASSERT(port
->fp_topology
== FC_TOP_PRIVATE_LOOP
);
5952 if (fctl_is_alpa_present(port
, pd
->pd_port_id
.port_id
) == FC_SUCCESS
) {
5956 cmn_err(CE_WARN
, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
5957 port
->fp_instance
, pd
->pd_port_id
.port_id
);
5962 fctl_is_alpa_present(fc_local_port_t
*port
, uchar_t alpa
)
5966 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
5967 ASSERT(port
->fp_topology
== FC_TOP_PRIVATE_LOOP
);
5969 for (index
= 0; index
< port
->fp_lilp_map
.lilp_length
; index
++) {
5970 if (port
->fp_lilp_map
.lilp_alpalist
[index
] == alpa
) {
5971 return (FC_SUCCESS
);
5975 return (FC_FAILURE
);
5980 fctl_lookup_pd_by_did(fc_local_port_t
*port
, uint32_t d_id
)
5983 struct pwwn_hash
*head
;
5984 fc_remote_port_t
*pd
;
5986 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
5988 for (index
= 0; index
< pwwn_table_size
; index
++) {
5989 head
= &port
->fp_pwwn_table
[index
];
5990 pd
= head
->pwwn_head
;
5992 while (pd
!= NULL
) {
5993 mutex_enter(&pd
->pd_mutex
);
5994 if (pd
->pd_port_id
.port_id
== d_id
) {
5995 mutex_exit(&pd
->pd_mutex
);
5998 mutex_exit(&pd
->pd_mutex
);
5999 pd
= pd
->pd_wwn_hnext
;
6011 fc_trace_debug(fc_trace_logq_t
*logq
, caddr_t name
, int dflag
, int dlevel
,
6012 int errno
, const char *fmt
, ...)
6014 char buf
[FC_MAX_TRACE_BUF_LEN
+ 3]; /* 3 is for "\n" */
6019 if ((dlevel
& dflag
) == 0) {
6024 cnt
= snprintf(buf
, FC_MAX_TRACE_BUF_LEN
+ 1, "%d=>%s::",
6025 logq
->il_id
++, name
);
6027 cnt
= snprintf(buf
, FC_MAX_TRACE_BUF_LEN
+ 1, "%d=>trace::",
6031 if (cnt
< FC_MAX_TRACE_BUF_LEN
) {
6033 cnt
+= vsnprintf(buf
+ cnt
, FC_MAX_TRACE_BUF_LEN
+ 1 - cnt
,
6038 if (cnt
> FC_MAX_TRACE_BUF_LEN
) {
6039 cnt
= FC_MAX_TRACE_BUF_LEN
;
6041 if (errno
&& (cnt
< FC_MAX_TRACE_BUF_LEN
)) {
6042 cnt
+= snprintf(buf
+ cnt
, FC_MAX_TRACE_BUF_LEN
+ 1 - cnt
,
6043 "error=0x%x\n", errno
);
6045 (void) snprintf(buf
+ cnt
, FC_MAX_TRACE_BUF_LEN
+ 3 - cnt
, "\n");
6047 if (logq
&& (dlevel
& FC_TRACE_LOG_BUF
) != 0) {
6048 fc_trace_logmsg(logq
, buf
, dlevel
);
6052 * We do not want to print the log numbers that appear as
6053 * random numbers at the console and messages files, to
6056 if ((bufptr
= strchr(buf
, '>')) == NULL
) {
6058 * We would have added the a string with "=>" above and so,
6059 * ideally, we should not get here at all. But, if we do,
6060 * we'll just use the full buf.
6067 switch (dlevel
& FC_TRACE_LOG_MASK
) {
6068 case FC_TRACE_LOG_CONSOLE
:
6069 cmn_err(CE_WARN
, "%s", bufptr
);
6072 case FC_TRACE_LOG_CONSOLE_MSG
:
6073 cmn_err(CE_WARN
, "%s", bufptr
);
6076 case FC_TRACE_LOG_MSG
:
6077 cmn_err(CE_WARN
, "!%s", bufptr
);
6087 * This function can block
6090 fc_trace_alloc_logq(int maxsize
)
6092 fc_trace_logq_t
*logq
;
6094 logq
= kmem_zalloc(sizeof (*logq
), KM_SLEEP
);
6096 mutex_init(&logq
->il_lock
, NULL
, MUTEX_DRIVER
, NULL
);
6097 logq
->il_hiwat
= maxsize
;
6098 logq
->il_flags
|= FC_TRACE_LOGQ_V2
;
6105 fc_trace_free_logq(fc_trace_logq_t
*logq
)
6107 mutex_enter(&logq
->il_lock
);
6108 while (logq
->il_msgh
) {
6109 fc_trace_freemsg(logq
);
6111 mutex_exit(&logq
->il_lock
);
6113 mutex_destroy(&logq
->il_lock
);
6114 kmem_free(logq
, sizeof (*logq
));
6120 fc_trace_logmsg(fc_trace_logq_t
*logq
, caddr_t buf
, int level
)
6123 fc_trace_dmsg_t
*dmsg
;
6125 dmsg
= kmem_alloc(sizeof (*dmsg
), KM_NOSLEEP
);
6127 mutex_enter(&logq
->il_lock
);
6129 mutex_exit(&logq
->il_lock
);
6134 gethrestime(&dmsg
->id_time
);
6136 dmsg
->id_size
= strlen(buf
) + 1;
6137 dmsg
->id_buf
= kmem_alloc(dmsg
->id_size
, KM_NOSLEEP
);
6138 if (dmsg
->id_buf
== NULL
) {
6139 kmem_free(dmsg
, sizeof (*dmsg
));
6141 mutex_enter(&logq
->il_lock
);
6143 mutex_exit(&logq
->il_lock
);
6147 bcopy(buf
, dmsg
->id_buf
, strlen(buf
));
6148 dmsg
->id_buf
[strlen(buf
)] = '\0';
6150 mutex_enter(&logq
->il_lock
);
6152 logq
->il_size
+= dmsg
->id_size
;
6153 if (logq
->il_size
>= logq
->il_hiwat
) {
6158 fc_trace_freemsg(logq
);
6161 dmsg
->id_next
= NULL
;
6162 if (logq
->il_msgt
) {
6163 logq
->il_msgt
->id_next
= dmsg
;
6165 ASSERT(logq
->il_msgh
== NULL
);
6166 logq
->il_msgh
= dmsg
;
6168 logq
->il_msgt
= dmsg
;
6170 mutex_exit(&logq
->il_lock
);
6175 fc_trace_freemsg(fc_trace_logq_t
*logq
)
6177 fc_trace_dmsg_t
*dmsg
;
6179 ASSERT(MUTEX_HELD(&logq
->il_lock
));
6181 if ((dmsg
= logq
->il_msgh
) != NULL
) {
6182 logq
->il_msgh
= dmsg
->id_next
;
6183 if (logq
->il_msgh
== NULL
) {
6184 logq
->il_msgt
= NULL
;
6187 logq
->il_size
-= dmsg
->id_size
;
6188 kmem_free(dmsg
->id_buf
, dmsg
->id_size
);
6189 kmem_free(dmsg
, sizeof (*dmsg
));
6191 ASSERT(logq
->il_msgt
== NULL
);
6196 * Used by T11 FC-HBA to fetch discovered ports by index.
6197 * Returns NULL if the index isn't valid.
6200 fctl_lookup_pd_by_index(fc_local_port_t
*port
, uint32_t index
)
6204 struct pwwn_hash
*head
;
6205 fc_remote_port_t
*pd
;
6207 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
6210 outer
< pwwn_table_size
&& match
<= index
;
6212 head
= &port
->fp_pwwn_table
[outer
];
6213 pd
= head
->pwwn_head
;
6214 if (pd
!= NULL
) match
++;
6216 while (pd
!= NULL
&& match
<= index
) {
6217 pd
= pd
->pd_wwn_hnext
;
6218 if (pd
!= NULL
) match
++;
6226 * Search for a matching Node or Port WWN in the discovered port list
6229 fctl_lookup_pd_by_wwn(fc_local_port_t
*port
, la_wwn_t wwn
)
6232 struct pwwn_hash
*head
;
6233 fc_remote_port_t
*pd
;
6235 ASSERT(MUTEX_HELD(&port
->fp_mutex
));
6237 for (index
= 0; index
< pwwn_table_size
; index
++) {
6238 head
= &port
->fp_pwwn_table
[index
];
6239 pd
= head
->pwwn_head
;
6241 while (pd
!= NULL
) {
6242 mutex_enter(&pd
->pd_mutex
);
6243 if (bcmp(pd
->pd_port_name
.raw_wwn
, wwn
.raw_wwn
,
6244 sizeof (la_wwn_t
)) == 0) {
6245 mutex_exit(&pd
->pd_mutex
);
6248 if (bcmp(pd
->pd_remote_nodep
->fd_node_name
.raw_wwn
,
6249 wwn
.raw_wwn
, sizeof (la_wwn_t
)) == 0) {
6250 mutex_exit(&pd
->pd_mutex
);
6253 mutex_exit(&pd
->pd_mutex
);
6254 pd
= pd
->pd_wwn_hnext
;
6263 * Count the number of ports on this adapter.
6264 * This routine will walk the port list and count up the number of adapters
6265 * with matching fp_hba_port_attrs.hba_fru_details.high and
6266 * fp_hba_port_attrs.hba_fru_details.low.
6268 * port->fp_mutex must not be held.
6271 fctl_count_fru_ports(fc_local_port_t
*port
, int npivflag
)
6273 fca_hba_fru_details_t
*fru
;
6274 fc_fca_port_t
*fca_port
;
6275 fc_local_port_t
*tmpPort
= NULL
;
6278 mutex_enter(&fctl_port_lock
);
6280 mutex_enter(&port
->fp_mutex
);
6281 fru
= &port
->fp_hba_port_attrs
.hba_fru_details
;
6283 /* Detect FCA drivers that don't support linking HBA ports */
6284 if (fru
->high
== 0 && fru
->low
== 0 && fru
->port_index
== 0) {
6285 mutex_exit(&port
->fp_mutex
);
6286 mutex_exit(&fctl_port_lock
);
6290 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
6291 fca_port
= fca_port
->port_next
) {
6292 tmpPort
= fca_port
->port_handle
;
6293 if (tmpPort
== port
) {
6296 mutex_enter(&tmpPort
->fp_mutex
);
6299 * If an FCA driver returns unique fru->high and fru->low for
6300 * ports on the same card, there is no way for the transport
6301 * layer to determine that the two ports on the same FRU. So,
6302 * the discovery of the ports on a same FRU is limited to what
6303 * the FCA driver can report back.
6305 if (tmpPort
->fp_hba_port_attrs
.hba_fru_details
.high
==
6307 tmpPort
->fp_hba_port_attrs
.hba_fru_details
.low
==
6309 /* Now double check driver */
6310 if (strncmp(port
->fp_hba_port_attrs
.driver_name
,
6311 tmpPort
->fp_hba_port_attrs
.driver_name
,
6312 FCHBA_DRIVER_NAME_LEN
) == 0) {
6314 (tmpPort
->fp_npiv_type
!= FC_NPIV_PORT
)) {
6317 } /* Else, different FCA driver */
6318 } /* Else not the same HBA FRU */
6319 mutex_exit(&tmpPort
->fp_mutex
);
6322 mutex_exit(&port
->fp_mutex
);
6323 mutex_exit(&fctl_port_lock
);
6329 fctl_local_port_list_add(fc_fca_port_t
*list
, fc_local_port_t
*port
)
6331 fc_fca_port_t
*tmp
= list
, *newentry
= NULL
;
6333 newentry
= kmem_zalloc(sizeof (fc_fca_port_t
), KM_NOSLEEP
);
6334 if (newentry
== NULL
) {
6337 newentry
->port_handle
= port
;
6342 while (tmp
->port_next
!= NULL
) tmp
= tmp
->port_next
;
6343 tmp
->port_next
= newentry
;
6349 fctl_local_port_list_free(fc_fca_port_t
*list
)
6351 fc_fca_port_t
*tmp
= list
, *nextentry
;
6357 while (tmp
!= NULL
) {
6358 nextentry
= tmp
->port_next
;
6359 kmem_free(tmp
, sizeof (*tmp
));
6365 * Fetch another port on the HBA FRU based on index.
6366 * Returns NULL if index not found.
6368 * port->fp_mutex must not be held.
6371 fctl_get_adapter_port_by_index(fc_local_port_t
*port
, uint32_t port_index
)
6373 fca_hba_fru_details_t
*fru
;
6374 fc_fca_port_t
*fca_port
;
6375 fc_local_port_t
*tmpPort
= NULL
;
6376 fc_fca_port_t
*list
= NULL
, *tmpEntry
;
6377 fc_local_port_t
*phyPort
, *virPort
= NULL
;
6378 int index
, phyPortNum
= 0;
6380 mutex_enter(&fctl_port_lock
);
6382 mutex_enter(&port
->fp_mutex
);
6383 fru
= &port
->fp_hba_port_attrs
.hba_fru_details
;
6385 /* Are we looking for this port? */
6386 if (fru
->port_index
== port_index
) {
6387 mutex_exit(&port
->fp_mutex
);
6388 mutex_exit(&fctl_port_lock
);
6392 /* Detect FCA drivers that don't support linking HBA ports */
6393 if (fru
->high
== 0 && fru
->low
== 0 && fru
->port_index
== 0) {
6394 mutex_exit(&port
->fp_mutex
);
6395 mutex_exit(&fctl_port_lock
);
6399 list
= fctl_local_port_list_add(list
, port
);
6401 /* Loop through all known ports */
6402 for (fca_port
= fctl_fca_portlist
; fca_port
!= NULL
;
6403 fca_port
= fca_port
->port_next
) {
6404 tmpPort
= fca_port
->port_handle
;
6405 if (tmpPort
== port
) {
6406 /* Skip the port that was passed in as the argument */
6409 mutex_enter(&tmpPort
->fp_mutex
);
6411 /* See if this port is on the same HBA FRU (fast check) */
6412 if (tmpPort
->fp_hba_port_attrs
.hba_fru_details
.high
==
6414 tmpPort
->fp_hba_port_attrs
.hba_fru_details
.low
==
6416 /* Now double check driver (slower check) */
6417 if (strncmp(port
->fp_hba_port_attrs
.driver_name
,
6418 tmpPort
->fp_hba_port_attrs
.driver_name
,
6419 FCHBA_DRIVER_NAME_LEN
) == 0) {
6422 &tmpPort
->fp_hba_port_attrs
.hba_fru_details
;
6423 /* Check for the matching port_index */
6424 if ((tmpPort
->fp_npiv_type
!= FC_NPIV_PORT
) &&
6425 (fru
->port_index
== port_index
)) {
6427 mutex_exit(&tmpPort
->fp_mutex
);
6428 mutex_exit(&port
->fp_mutex
);
6429 mutex_exit(&fctl_port_lock
);
6430 fctl_local_port_list_free(list
);
6433 if (tmpPort
->fp_npiv_type
!= FC_NPIV_PORT
) {
6434 (void) fctl_local_port_list_add(list
,
6438 } /* Else, different FCA driver */
6439 } /* Else not the same HBA FRU */
6440 mutex_exit(&tmpPort
->fp_mutex
);
6444 /* scan all physical port on same chip to find virtual port */
6446 index
= phyPortNum
- 1;
6448 while (index
< port_index
) {
6449 if (tmpEntry
== NULL
) {
6452 if (virPort
== NULL
) {
6453 phyPort
= tmpEntry
->port_handle
;
6454 virPort
= phyPort
->fp_port_next
;
6455 if (virPort
== NULL
) {
6456 tmpEntry
= tmpEntry
->port_next
;
6460 virPort
= virPort
->fp_port_next
;
6462 if (virPort
== phyPort
) {
6463 tmpEntry
= tmpEntry
->port_next
;
6469 mutex_exit(&port
->fp_mutex
);
6470 mutex_exit(&fctl_port_lock
);
6472 fctl_local_port_list_free(list
);
6480 fctl_busy_port(fc_local_port_t
*port
)
6482 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
6484 mutex_enter(&port
->fp_mutex
);
6485 if (port
->fp_soft_state
& FP_SOFT_NO_PMCOMP
) {
6487 * If fctl_busy_port() is called before we've registered our
6488 * PM components, we return success. We need to be aware of
6489 * this because the caller will eventually call fctl_idle_port.
6490 * This wouldn't be a problem except that if we have
6491 * registered our PM components in the meantime, we will
6492 * then be idling a component that was never busied. PM
6493 * will be very unhappy if we do this. Thus, we keep
6494 * track of this with port->fp_pm_busy_nocomp.
6496 port
->fp_pm_busy_nocomp
++;
6497 mutex_exit(&port
->fp_mutex
);
6501 mutex_exit(&port
->fp_mutex
);
6503 if (pm_busy_component(port
->fp_port_dip
,
6504 FP_PM_COMPONENT
) != DDI_SUCCESS
) {
6505 mutex_enter(&port
->fp_mutex
);
6507 mutex_exit(&port
->fp_mutex
);
6511 mutex_enter(&port
->fp_mutex
);
6512 if (port
->fp_pm_level
== FP_PM_PORT_DOWN
) {
6513 mutex_exit(&port
->fp_mutex
);
6514 if (pm_raise_power(port
->fp_port_dip
, FP_PM_COMPONENT
,
6515 FP_PM_PORT_UP
) != DDI_SUCCESS
) {
6517 mutex_enter(&port
->fp_mutex
);
6519 mutex_exit(&port
->fp_mutex
);
6521 (void) pm_idle_component(port
->fp_port_dip
,
6527 mutex_exit(&port
->fp_mutex
);
6532 fctl_idle_port(fc_local_port_t
*port
)
6534 ASSERT(!MUTEX_HELD(&port
->fp_mutex
));
6536 mutex_enter(&port
->fp_mutex
);
6539 * If port->fp_pm_busy_nocomp is > 0, that means somebody had
6540 * called fctl_busy_port prior to us registering our PM components.
6541 * In that case, we just decrement fp_pm_busy_nocomp and return.
6544 if (port
->fp_pm_busy_nocomp
> 0) {
6545 port
->fp_pm_busy_nocomp
--;
6546 mutex_exit(&port
->fp_mutex
);
6551 mutex_exit(&port
->fp_mutex
);
6553 (void) pm_idle_component(port
->fp_port_dip
, FP_PM_COMPONENT
);
6557 * Function: fctl_tc_timer
6559 * Description: Resets the value of the timed counter.
6561 * Arguments: *tc Timed counter
6563 * Return Value: Nothing
6565 * Context: Kernel context.
6568 fctl_tc_timer(void *arg
)
6570 timed_counter_t
*tc
= (timed_counter_t
*)arg
;
6573 ASSERT(tc
->sig
== tc
);
6575 mutex_enter(&tc
->mutex
);
6577 tc
->active
= B_FALSE
;
6580 mutex_exit(&tc
->mutex
);
6584 * Function: fctl_tc_constructor
6586 * Description: Constructs a timed counter.
6588 * Arguments: *tc Address where the timed counter will reside.
6589 * max_value Maximum value the counter is allowed to take.
6590 * timer Number of microseconds after which the counter
6591 * will be reset. The timer is started when the
6592 * value of the counter goes from 0 to 1.
6594 * Return Value: Nothing
6596 * Context: Kernel context.
6599 fctl_tc_constructor(timed_counter_t
*tc
, uint32_t max_value
, clock_t timer
)
6602 ASSERT(tc
->sig
!= tc
);
6604 bzero(tc
, sizeof (*tc
));
6605 mutex_init(&tc
->mutex
, NULL
, MUTEX_DRIVER
, NULL
);
6606 tc
->timer
= drv_usectohz(timer
);
6607 tc
->active
= B_FALSE
;
6608 tc
->maxed_out
= B_FALSE
;
6609 tc
->max_value
= max_value
;
6614 * Function: fctl_tc_destructor
6616 * Description: Destroyes a timed counter.
6618 * Arguments: *tc Timed counter to destroy.
6620 * Return Value: Nothing
6622 * Context: Kernel context.
6625 fctl_tc_destructor(timed_counter_t
*tc
)
6628 ASSERT(tc
->sig
== tc
);
6629 ASSERT(!mutex_owned(&tc
->mutex
));
6631 mutex_enter(&tc
->mutex
);
6633 tc
->active
= B_FALSE
;
6634 mutex_exit(&tc
->mutex
);
6635 (void) untimeout(tc
->tid
);
6636 mutex_enter(&tc
->mutex
);
6639 mutex_exit(&tc
->mutex
);
6640 mutex_destroy(&tc
->mutex
);
6644 * Function: fctl_tc_increment
6646 * Description: Increments a timed counter
6648 * Arguments: *tc Timed counter to increment.
6650 * Return Value: B_TRUE Counter reached the max value.
6651 * B_FALSE Counter hasn't reached the max value.
6653 * Context: Kernel or interrupt context.
6656 fctl_tc_increment(timed_counter_t
*tc
)
6659 ASSERT(tc
->sig
== tc
);
6661 mutex_enter(&tc
->mutex
);
6662 if (!tc
->maxed_out
) {
6663 /* Hasn't maxed out yet. */
6665 if (tc
->counter
>= tc
->max_value
) {
6666 /* Just maxed out. */
6667 tc
->maxed_out
= B_TRUE
;
6670 tc
->tid
= timeout(fctl_tc_timer
, tc
, tc
->timer
);
6671 tc
->active
= B_TRUE
;
6674 mutex_exit(&tc
->mutex
);
6676 return (tc
->maxed_out
);
6680 * Function: fctl_tc_reset
6682 * Description: Resets a timed counter. The caller of this function has to
6683 * to make sure that while in fctl_tc_reset() fctl_tc_increment()
6686 * Arguments: *tc Timed counter to reset.
6688 * Return Value: 0 Counter reached the max value.
6689 * Not 0 Counter hasn't reached the max value.
6691 * Context: Kernel or interrupt context.
6694 fctl_tc_reset(timed_counter_t
*tc
)
6697 ASSERT(tc
->sig
== tc
);
6699 mutex_enter(&tc
->mutex
);
6701 tc
->maxed_out
= B_FALSE
;
6703 tc
->active
= B_FALSE
;
6704 (void) untimeout(tc
->tid
);
6706 mutex_exit(&tc
->mutex
);
6710 fc_ulp_log_device_event(opaque_t port_handle
, int type
)
6712 fc_local_port_t
*port
= port_handle
;
6713 nvlist_t
*attr_list
;
6715 if (nvlist_alloc(&attr_list
, NV_UNIQUE_NAME_TYPE
,
6716 KM_SLEEP
) != DDI_SUCCESS
) {
6720 if (nvlist_add_uint32(attr_list
, "instance",
6721 port
->fp_instance
) != DDI_SUCCESS
) {
6725 if (nvlist_add_byte_array(attr_list
, "port-wwn",
6726 port
->fp_service_params
.nport_ww_name
.raw_wwn
,
6727 sizeof (la_wwn_t
)) != DDI_SUCCESS
) {
6731 (void) ddi_log_sysevent(port
->fp_port_dip
, DDI_VENDOR_SUNW
, EC_SUNFC
,
6732 (type
== FC_ULP_DEVICE_ONLINE
) ?
6733 ESC_SUNFC_DEVICE_ONLINE
: ESC_SUNFC_DEVICE_OFFLINE
,
6734 attr_list
, NULL
, DDI_SLEEP
);
6735 nvlist_free(attr_list
);
6739 nvlist_free(attr_list
);