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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * fcsm - ULP Module for Fibre Channel SAN Management
30 #include <sys/types.h>
33 #include <sys/scsi/scsi.h>
35 #include <sys/byteorder.h>
36 #include <sys/fibre-channel/fc.h>
37 #include <sys/fibre-channel/impl/fc_ulpif.h>
38 #include <sys/fibre-channel/ulp/fcsm.h>
41 #define FCSM_VERSION "20090729-1.28"
42 #define FCSM_NAME_VERSION "SunFC FCSM v" FCSM_VERSION
44 /* Global Variables */
45 static char fcsm_name
[] = "FCSM";
46 static void *fcsm_state
= NULL
;
47 static kmutex_t fcsm_global_mutex
;
48 static uint32_t fcsm_flag
= FCSM_IDLE
;
49 static dev_info_t
*fcsm_dip
= NULL
;
50 static fcsm_t
*fcsm_port_head
= NULL
;
51 static kmem_cache_t
*fcsm_job_cache
= NULL
;
52 static int fcsm_num_attaching
= 0;
53 static int fcsm_num_detaching
= 0;
54 static int fcsm_detached
= 0;
56 static int fcsm_max_cmd_retries
= FCSM_MAX_CMD_RETRIES
;
57 static int fcsm_retry_interval
= FCSM_RETRY_INTERVAL
;
58 static int fcsm_retry_ticker
= FCSM_RETRY_TICKER
;
59 static int fcsm_offline_ticker
= FCSM_OFFLINE_TICKER
;
60 static int fcsm_max_job_retries
= FCSM_MAX_JOB_RETRIES
;
61 static clock_t fcsm_retry_ticks
;
62 static clock_t fcsm_offline_ticks
;
67 uint32_t fcsm_debug
= 0;
71 /* Character/Block entry points */
72 struct cb_ops fcsm_cb_ops
= {
74 fcsm_close
, /* close */
80 fcsm_ioctl
, /* ioctl */
86 NULL
, /* streams info */
93 struct dev_ops fcsm_ops
= {
96 fcsm_getinfo
, /* get info */
97 nulldev
, /* identify (obsolete) */
98 nulldev
, /* probe (not required for self-identifying devices) */
99 fcsm_attach
, /* attach */
100 fcsm_detach
, /* detach */
102 &fcsm_cb_ops
, /* char/block entry points structure for leaf drivers */
103 NULL
, /* bus operations for nexus driver */
104 NULL
/* power management */
108 struct modldrv modldrv
= {
114 struct modlinkage modlinkage
= {
120 static fc_ulp_modinfo_t fcsm_modinfo
= {
121 &fcsm_modinfo
, /* ulp_handle */
122 FCTL_ULP_MODREV_4
, /* ulp_rev */
123 FC_TYPE_FC_SERVICES
, /* ulp_type */
124 fcsm_name
, /* ulp_name */
125 0, /* ulp_statec_mask: get all statec callbacks */
126 fcsm_port_attach
, /* ulp_port_attach */
127 fcsm_port_detach
, /* ulp_port_detach */
128 fcsm_port_ioctl
, /* ulp_port_ioctl */
129 fcsm_els_cb
, /* ulp_els_callback */
130 fcsm_data_cb
, /* ulp_data_callback */
131 fcsm_statec_cb
/* ulp_statec_callback */
134 struct fcsm_xlat_pkt_state
{
137 } fcsm_xlat_pkt_state
[] = {
138 { FC_PKT_SUCCESS
, FC_SUCCESS
},
139 { FC_PKT_REMOTE_STOP
, FC_FAILURE
},
140 { FC_PKT_LOCAL_RJT
, FC_TRANSPORT_ERROR
},
141 { FC_PKT_NPORT_RJT
, FC_PREJECT
},
142 { FC_PKT_FABRIC_RJT
, FC_FREJECT
},
143 { FC_PKT_LOCAL_BSY
, FC_TRAN_BUSY
},
144 { FC_PKT_TRAN_BSY
, FC_TRAN_BUSY
},
145 { FC_PKT_NPORT_BSY
, FC_PBUSY
},
146 { FC_PKT_FABRIC_BSY
, FC_FBUSY
},
147 { FC_PKT_LS_RJT
, FC_PREJECT
},
148 { FC_PKT_BA_RJT
, FC_PREJECT
},
149 { FC_PKT_TIMEOUT
, FC_FAILURE
},
150 { FC_PKT_FS_RJT
, FC_FAILURE
},
151 { FC_PKT_TRAN_ERROR
, FC_TRANSPORT_ERROR
},
152 { FC_PKT_FAILURE
, FC_FAILURE
},
153 { FC_PKT_PORT_OFFLINE
, FC_OFFLINE
},
154 { FC_PKT_ELS_IN_PROGRESS
, FC_FAILURE
}
157 struct fcsm_xlat_port_state
{
158 uint32_t xlat_pstate
;
159 caddr_t xlat_state_str
;
160 } fcsm_xlat_port_state
[] = {
161 { FC_STATE_OFFLINE
, "OFFLINE" },
162 { FC_STATE_ONLINE
, "ONLINE" },
163 { FC_STATE_LOOP
, "LOOP" },
164 { FC_STATE_NAMESERVICE
, "NAMESERVICE" },
165 { FC_STATE_RESET
, "RESET" },
166 { FC_STATE_RESET_REQUESTED
, "RESET_REQUESTED" },
167 { FC_STATE_LIP
, "LIP" },
168 { FC_STATE_LIP_LBIT_SET
, "LIP_LBIT_SET" },
169 { FC_STATE_DEVICE_CHANGE
, "DEVICE_CHANGE" },
170 { FC_STATE_TARGET_PORT_RESET
, "TARGET_PORT_RESET" }
173 struct fcsm_xlat_topology
{
175 caddr_t xlat_top_str
;
176 } fcsm_xlat_topology
[] = {
177 { FC_TOP_UNKNOWN
, "UNKNOWN" },
178 { FC_TOP_PRIVATE_LOOP
, "Private Loop" },
179 { FC_TOP_PUBLIC_LOOP
, "Public Loop" },
180 { FC_TOP_FABRIC
, "Fabric" },
181 { FC_TOP_PT_PT
, "Point-to-Point" },
182 { FC_TOP_NO_NS
, "NO_NS" }
185 struct fcsm_xlat_dev_type
{
188 } fcsm_xlat_dev_type
[] = {
189 { PORT_DEVICE_NOCHANGE
, "No Change" },
190 { PORT_DEVICE_NEW
, "New" },
191 { PORT_DEVICE_OLD
, "Old" },
192 { PORT_DEVICE_CHANGED
, "Changed" },
193 { PORT_DEVICE_DELETE
, "Delete" },
194 { PORT_DEVICE_USER_LOGIN
, "User Login" },
195 { PORT_DEVICE_USER_LOGOUT
, "User Logout" },
196 { PORT_DEVICE_USER_CREATE
, "User Create" },
197 { PORT_DEVICE_USER_DELETE
, "User Delete" }
205 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "_init"));
207 fcsm_retry_ticks
= drv_usectohz(fcsm_retry_ticker
* 1000 * 1000);
208 fcsm_offline_ticks
= drv_usectohz(fcsm_offline_ticker
* 1000 * 1000);
210 if (rval
= ddi_soft_state_init(&fcsm_state
, sizeof (fcsm_t
),
211 FCSM_INIT_INSTANCES
)) {
212 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
213 "_init: ddi_soft_state_init failed");
217 mutex_init(&fcsm_global_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
219 fcsm_job_cache
= kmem_cache_create("fcsm_job_cache",
220 sizeof (fcsm_job_t
), 8, fcsm_job_cache_constructor
,
221 fcsm_job_cache_destructor
, NULL
, NULL
, NULL
, 0);
223 if (fcsm_job_cache
== NULL
) {
224 mutex_destroy(&fcsm_global_mutex
);
225 ddi_soft_state_fini(&fcsm_state
);
230 * Now call fc_ulp_add to add this ULP in the transport layer
231 * database. This will cause 'ulp_port_attach' callback function
234 rval
= fc_ulp_add(&fcsm_modinfo
);
237 case FC_ULP_SAMEMODULE
:
238 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
239 "_init: FC SAN Management module is already "
240 "registered with transport layer");
244 case FC_ULP_SAMETYPE
:
245 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
246 "_init: Another module with same type 0x%x is "
247 "already registered with transport layer",
248 fcsm_modinfo
.ulp_type
);
253 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
254 "_init: Please upgrade this module. Current "
255 "version 0x%x is not the most recent version",
256 fcsm_modinfo
.ulp_rev
);
260 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
261 "_init: fc_ulp_add failed with status 0x%x", rval
);
265 kmem_cache_destroy(fcsm_job_cache
);
266 mutex_destroy(&fcsm_global_mutex
);
267 ddi_soft_state_fini(&fcsm_state
);
271 if ((rval
= mod_install(&modlinkage
)) != 0) {
272 FCSM_DEBUG(SMDL_ERR
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
273 "_init: mod_install failed with status 0x%x", rval
));
274 (void) fc_ulp_remove(&fcsm_modinfo
);
275 kmem_cache_destroy(fcsm_job_cache
);
276 mutex_destroy(&fcsm_global_mutex
);
277 ddi_soft_state_fini(&fcsm_state
);
292 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "_fini"));
295 * don't start cleaning up until we know that the module remove
296 * has worked -- if this works, then we know that each instance
297 * has successfully been DDI_DETACHed
299 if ((rval
= mod_remove(&modlinkage
)) != 0) {
304 status
= fc_ulp_remove(&fcsm_modinfo
);
306 FCSM_DEBUG(SMDL_ERR
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
307 "_fini: fc_ulp_remove failed with status 0x%x", status
));
310 (void) fc_ulp_remove(&fcsm_modinfo
);
316 * It is possible to modunload fcsm manually, which will cause
317 * a bypass of all the port_detach functionality. We may need
318 * to force that code path to be executed to properly clean up
321 fcsm_force_port_detach_all();
323 kmem_cache_destroy(fcsm_job_cache
);
324 mutex_destroy(&fcsm_global_mutex
);
325 ddi_soft_state_fini(&fcsm_state
);
332 _info(struct modinfo
*modinfop
)
334 return (mod_info(&modlinkage
, modinfop
));
339 fcsm_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
341 int rval
= DDI_FAILURE
;
343 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
344 "attach: cmd 0x%x", cmd
));
348 mutex_enter(&fcsm_global_mutex
);
349 if (fcsm_dip
!= NULL
) {
350 mutex_exit(&fcsm_global_mutex
);
351 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
352 "attach: duplicate attach of fcsm!!"));
359 * The detach routine cleans up all the port instances
360 * i.e. it detaches all ports.
361 * If _fini never got called after detach, then
362 * perform an fc_ulp_remove() followed by fc_ulp_add()
363 * to ensure that port_attach callbacks are called
369 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
370 "attach: rebinding to transport driver"));
372 mutex_exit(&fcsm_global_mutex
);
374 (void) fc_ulp_remove(&fcsm_modinfo
);
377 * Reset the detached flag, so that ports can attach
379 mutex_enter(&fcsm_global_mutex
);
381 mutex_exit(&fcsm_global_mutex
);
383 status
= fc_ulp_add(&fcsm_modinfo
);
387 * ULP add failed. So set the
388 * detached flag again
390 mutex_enter(&fcsm_global_mutex
);
392 mutex_exit(&fcsm_global_mutex
);
395 case FC_ULP_SAMEMODULE
:
396 fcsm_display(CE_WARN
, SM_LOG
, NULL
,
397 NULL
, "attach: FC SAN Management "
399 "registered with transport layer");
402 case FC_ULP_SAMETYPE
:
403 fcsm_display(CE_WARN
, SM_LOG
, NULL
,
404 NULL
, "attach: Another module with "
405 "same type 0x%x is already "
406 "registered with transport layer",
407 fcsm_modinfo
.ulp_type
);
411 fcsm_display(CE_WARN
, SM_LOG
, NULL
,
412 NULL
, "attach: Please upgrade this "
413 "module. Current version 0x%x is "
414 "not the most recent version",
415 fcsm_modinfo
.ulp_rev
);
418 fcsm_display(CE_WARN
, SM_LOG
, NULL
,
419 NULL
, "attach: fc_ulp_add failed "
420 "with status 0x%x", status
);
428 mutex_enter(&fcsm_global_mutex
);
431 /* Create a minor node */
432 if (ddi_create_minor_node(fcsm_dip
, "fcsm", S_IFCHR
,
433 0, DDI_PSEUDO
, 0) == DDI_SUCCESS
) {
434 /* Announce presence of the device */
435 mutex_exit(&fcsm_global_mutex
);
440 mutex_exit(&fcsm_global_mutex
);
441 fcsm_display(CE_WARN
, SM_LOG_AND_CONSOLE
,
442 NULL
, NULL
, "attach: create minor node failed");
451 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
452 "attach: unknown cmd 0x%x dip 0x%p", cmd
, dip
));
461 fcsm_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
464 int rval
= DDI_SUCCESS
;
466 instance
= getminor((dev_t
)arg
);
469 case DDI_INFO_DEVT2INSTANCE
:
470 *result
= (void *)(long)instance
; /* minor number is instance */
473 case DDI_INFO_DEVT2DEVINFO
:
474 mutex_enter(&fcsm_global_mutex
);
475 *result
= (void *)fcsm_dip
;
476 mutex_exit(&fcsm_global_mutex
);
490 fcsm_port_attach(opaque_t ulph
, fc_ulp_port_info_t
*pinfo
,
491 fc_attach_cmd_t cmd
, uint32_t s_id
)
494 int rval
= FC_FAILURE
;
496 instance
= ddi_get_instance(pinfo
->port_dip
);
499 * Set the attaching flag, so that fcsm_detach will fail, if
500 * port attach is in progress.
502 mutex_enter(&fcsm_global_mutex
);
504 mutex_exit(&fcsm_global_mutex
);
506 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
507 "port_attach: end. detach in progress. failing attach "
508 "instance 0x%x", instance
));
509 return (((cmd
== FC_CMD_POWER_UP
) || (cmd
== FC_CMD_RESUME
)) ?
510 FC_FAILURE_SILENT
: FC_FAILURE
);
513 fcsm_num_attaching
++;
514 mutex_exit(&fcsm_global_mutex
);
518 if (fcsm_handle_port_attach(pinfo
, s_id
, instance
)
520 ASSERT(ddi_get_soft_state(fcsm_state
,
528 case FC_CMD_POWER_UP
: {
530 char fcsm_pathname
[MAXPATHLEN
];
532 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
533 "port_attach: cmd 0x%x instance 0x%x", cmd
, instance
));
535 /* Get the soft state structure */
536 if ((fcsm
= ddi_get_soft_state(fcsm_state
, instance
)) == NULL
) {
537 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
538 "port_attach: instance 0x%x, cmd 0x%x "
539 "get softstate failed", instance
, cmd
));
543 ASSERT(fcsm
->sm_instance
== instance
);
545 /* If this instance is not attached, then return failure */
546 mutex_enter(&fcsm
->sm_mutex
);
547 if ((fcsm
->sm_flags
& FCSM_ATTACHED
) == 0) {
548 mutex_exit(&fcsm
->sm_mutex
);
549 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
550 "port_detach: port is not attached");
553 mutex_exit(&fcsm
->sm_mutex
);
555 if (fcsm_handle_port_resume(ulph
, pinfo
, cmd
, s_id
, fcsm
) !=
560 (void) ddi_pathname(fcsm
->sm_port_info
.port_dip
, fcsm_pathname
);
561 fcsm_display(CE_NOTE
, SM_LOG
, fcsm
, NULL
,
562 "attached to path %s", fcsm_pathname
);
568 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
569 "port_attach: unknown cmd 0x%x for port 0x%x",
574 mutex_enter(&fcsm_global_mutex
);
575 fcsm_num_attaching
--;
576 mutex_exit(&fcsm_global_mutex
);
582 fcsm_handle_port_attach(fc_ulp_port_info_t
*pinfo
, uint32_t s_id
, int instance
)
587 char fcsm_pathname
[MAXPATHLEN
];
589 /* Allocate a soft state structure for the port */
590 if (ddi_soft_state_zalloc(fcsm_state
, instance
) != DDI_SUCCESS
) {
591 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
592 "port_attach: instance 0x%x, soft state alloc failed",
594 return (DDI_FAILURE
);
597 if ((fcsm
= ddi_get_soft_state(fcsm_state
, instance
)) == NULL
) {
598 fcsm_display(CE_WARN
, SM_LOG
, NULL
, NULL
,
599 "port_attach: instance 0x%x, get soft state failed",
601 ddi_soft_state_free(fcsm_state
, instance
);
602 return (DDI_FAILURE
);
606 /* Initialize the mutex */
607 mutex_init(&fcsm
->sm_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
608 cv_init(&fcsm
->sm_job_cv
, NULL
, CV_DRIVER
, NULL
);
610 mutex_enter(&fcsm
->sm_mutex
);
611 fcsm
->sm_flags
|= FCSM_ATTACHING
;
613 fcsm
->sm_instance
= instance
;
614 fcsm
->sm_port_state
= pinfo
->port_state
;
617 * Make a copy of the port_information structure, since fctl
618 * uses a temporary structure.
620 fcsm
->sm_port_info
= *pinfo
; /* Structure copy !!! */
621 mutex_exit(&fcsm
->sm_mutex
);
624 (void) sprintf(name
, "fcsm%d_cmd_cache", fcsm
->sm_instance
);
625 fcsm
->sm_cmd_cache
= kmem_cache_create(name
,
626 sizeof (fcsm_cmd_t
) + pinfo
->port_fca_pkt_size
, 8,
627 fcsm_cmd_cache_constructor
, fcsm_cmd_cache_destructor
,
628 NULL
, (void *)fcsm
, NULL
, 0);
629 if (fcsm
->sm_cmd_cache
== NULL
) {
630 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
631 "port_attach: pkt cache create failed");
632 cv_destroy(&fcsm
->sm_job_cv
);
633 mutex_destroy(&fcsm
->sm_mutex
);
634 ddi_soft_state_free(fcsm_state
, instance
);
635 return (DDI_FAILURE
);
638 thread
= thread_create(NULL
, 0, fcsm_job_thread
,
639 (caddr_t
)fcsm
, 0, &p0
, TS_RUN
, v
.v_maxsyspri
-2);
640 if (thread
== NULL
) {
641 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
642 "port_attach: job thread create failed");
643 kmem_cache_destroy(fcsm
->sm_cmd_cache
);
644 cv_destroy(&fcsm
->sm_job_cv
);
645 mutex_destroy(&fcsm
->sm_mutex
);
646 ddi_soft_state_free(fcsm_state
, instance
);
647 return (DDI_FAILURE
);
650 fcsm
->sm_thread
= thread
;
652 /* Add this structure to fcsm global linked list */
653 mutex_enter(&fcsm_global_mutex
);
654 if (fcsm_port_head
== NULL
) {
655 fcsm_port_head
= fcsm
;
657 fcsm
->sm_next
= fcsm_port_head
;
658 fcsm_port_head
= fcsm
;
660 mutex_exit(&fcsm_global_mutex
);
662 mutex_enter(&fcsm
->sm_mutex
);
663 fcsm
->sm_flags
&= ~FCSM_ATTACHING
;
664 fcsm
->sm_flags
|= FCSM_ATTACHED
;
665 fcsm
->sm_port_top
= pinfo
->port_flags
;
666 fcsm
->sm_port_state
= pinfo
->port_state
;
667 if (pinfo
->port_acc_attr
== NULL
) {
669 * The corresponding FCA doesn't support DMA at all
671 fcsm
->sm_flags
|= FCSM_USING_NODMA_FCA
;
673 mutex_exit(&fcsm
->sm_mutex
);
675 (void) ddi_pathname(fcsm
->sm_port_info
.port_dip
, fcsm_pathname
);
676 fcsm_display(CE_NOTE
, SM_LOG
, fcsm
, NULL
,
677 "attached to path %s", fcsm_pathname
);
679 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
680 "port_attach: state <%s>(0x%x) topology <%s>(0x%x)",
681 fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo
->port_state
)),
683 fcsm_topology_to_str(pinfo
->port_flags
), pinfo
->port_flags
));
685 return (DDI_SUCCESS
);
689 fcsm_handle_port_resume(opaque_t ulph
, fc_ulp_port_info_t
*pinfo
,
690 fc_attach_cmd_t cmd
, uint32_t s_id
, fcsm_t
*fcsm
)
692 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
693 "port_resume: cmd 0x%x", cmd
));
695 mutex_enter(&fcsm
->sm_mutex
);
699 ASSERT(!(fcsm
->sm_flags
& FCSM_POWER_DOWN
));
700 fcsm
->sm_flags
&= ~FCSM_SUSPENDED
;
703 case FC_CMD_POWER_UP
:
704 /* If port is suspended, then no need to resume */
705 fcsm
->sm_flags
&= ~FCSM_POWER_DOWN
;
706 if (fcsm
->sm_flags
& FCSM_SUSPENDED
) {
707 mutex_exit(&fcsm
->sm_mutex
);
708 return (DDI_SUCCESS
);
712 mutex_exit(&fcsm
->sm_mutex
);
713 return (DDI_FAILURE
);
719 * Make a copy of the new port_information structure
721 fcsm
->sm_port_info
= *pinfo
; /* Structure copy !!! */
722 mutex_exit(&fcsm
->sm_mutex
);
724 fcsm_resume_port(fcsm
);
727 * Invoke state change processing.
728 * This will ensure that
729 * - offline timer is started if new port state changed to offline.
730 * - MGMT_SERVER_LOGIN flag is reset.
731 * - Port topology is updated.
733 fcsm_statec_cb(ulph
, (opaque_t
)pinfo
->port_handle
, pinfo
->port_state
,
734 pinfo
->port_flags
, NULL
, 0, s_id
);
736 return (DDI_SUCCESS
);
742 fcsm_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
744 int rval
= DDI_SUCCESS
;
750 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
751 "detach: start. cmd <DETACH>", cmd
));
753 mutex_enter(&fcsm_global_mutex
);
756 * If port attach/detach in progress, then wait for 5 seconds
757 * for them to complete.
759 if (fcsm_num_attaching
|| fcsm_num_detaching
) {
762 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
763 "detach: wait for port attach/detach to complete"));
766 while ((count
++ <= 30) &&
767 (fcsm_num_attaching
|| fcsm_num_detaching
)) {
768 mutex_exit(&fcsm_global_mutex
);
770 mutex_enter(&fcsm_global_mutex
);
773 /* Port attach/detach still in prog, so fail detach */
774 if (fcsm_num_attaching
|| fcsm_num_detaching
) {
775 mutex_exit(&fcsm_global_mutex
);
776 FCSM_DEBUG(SMDL_ERR
, (CE_WARN
, SM_LOG
, NULL
,
777 NULL
, "detach: Failing detach. port "
778 "attach/detach in progress"));
784 if (fcsm_port_head
== NULL
) {
785 /* Not much do, Succeed to detach. */
786 ddi_remove_minor_node(fcsm_dip
, NULL
);
789 mutex_exit(&fcsm_global_mutex
);
794 * Check to see, if any ports are active.
795 * If not, then set the DETACHING flag to indicate
796 * that they are being detached.
798 fcsm
= fcsm_port_head
;
799 while (fcsm
!= NULL
) {
801 mutex_enter(&fcsm
->sm_mutex
);
802 if (!(fcsm
->sm_flags
& FCSM_ATTACHED
) ||
803 fcsm
->sm_ncmds
|| fcsm
->sm_cb_count
) {
804 /* port is busy. We can't detach */
805 mutex_exit(&fcsm
->sm_mutex
);
809 fcsm
->sm_flags
|= FCSM_DETACHING
;
810 mutex_exit(&fcsm
->sm_mutex
);
812 fcsm
= fcsm
->sm_next
;
816 * If all ports could not be marked for detaching,
817 * then clear the flags and fail the detach.
818 * Also if a port attach is currently in progress
819 * then fail the detach.
821 if (fcsm
!= NULL
|| fcsm_num_attaching
|| fcsm_num_detaching
) {
823 * Some ports were busy, so can't detach.
824 * Clear the DETACHING flag and return failure
826 fcsm
= fcsm_port_head
;
827 while (fcsm
!= NULL
) {
828 mutex_enter(&fcsm
->sm_mutex
);
829 if (fcsm
->sm_flags
& FCSM_DETACHING
) {
830 fcsm
->sm_flags
&= ~FCSM_DETACHING
;
832 mutex_exit(&fcsm
->sm_mutex
);
834 fcsm
= fcsm
->sm_next
;
836 mutex_exit(&fcsm_global_mutex
);
837 return (DDI_FAILURE
);
841 * Mark all the detaching ports as detached, as we
842 * will be detaching them
844 fcsm
= fcsm_port_head
;
845 while (fcsm
!= NULL
) {
846 mutex_enter(&fcsm
->sm_mutex
);
847 fcsm
->sm_flags
&= ~FCSM_DETACHING
;
848 fcsm
->sm_flags
|= FCSM_DETACHED
;
849 mutex_exit(&fcsm
->sm_mutex
);
851 fcsm
= fcsm
->sm_next
;
854 mutex_exit(&fcsm_global_mutex
);
858 * Go ahead and detach the ports
860 mutex_enter(&fcsm_global_mutex
);
861 while (fcsm_port_head
!= NULL
) {
862 fcsm
= fcsm_port_head
;
863 mutex_exit(&fcsm_global_mutex
);
866 * Call fcsm_cleanup_port(). This cleansup and
867 * removes the fcsm structure from global linked list
869 fcsm_cleanup_port(fcsm
);
872 * Soft state cleanup done.
873 * Remember that fcsm struct doesn't exist anymore.
876 mutex_enter(&fcsm_global_mutex
);
879 ddi_remove_minor_node(fcsm_dip
, NULL
);
881 mutex_exit(&fcsm_global_mutex
);
890 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
891 "detach: unknown cmd 0x%x", cmd
));
896 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
897 "detach: end. cmd 0x%x, rval 0x%x", cmd
, rval
));
905 fcsm_force_port_detach_all(void)
909 fcsm
= fcsm_port_head
;
912 fcsm_cleanup_port(fcsm
);
914 * fcsm_cleanup_port will remove the current fcsm structure
915 * from the list, which will cause fcsm_port_head to point
916 * to what would have been the next structure on the list.
918 fcsm
= fcsm_port_head
;
925 fcsm_port_detach(opaque_t ulph
, fc_ulp_port_info_t
*pinfo
, fc_detach_cmd_t cmd
)
928 int rval
= FC_FAILURE
;
931 instance
= ddi_get_instance(pinfo
->port_dip
);
933 mutex_enter(&fcsm_global_mutex
);
935 mutex_exit(&fcsm_global_mutex
);
937 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
938 "port_detach: end. instance 0x%x, fcsm is detached",
942 fcsm_num_detaching
++; /* Set the flag */
943 mutex_exit(&fcsm_global_mutex
);
945 /* Get the soft state structure */
946 if ((fcsm
= ddi_get_soft_state(fcsm_state
, instance
)) == NULL
) {
947 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
948 "port_detach: instance 0x%x, cmd 0x%x get softstate failed",
950 mutex_enter(&fcsm_global_mutex
);
951 fcsm_num_detaching
--;
952 mutex_exit(&fcsm_global_mutex
);
956 ASSERT(fcsm
->sm_instance
== instance
);
958 /* If this instance is not attached, then fail the detach */
959 mutex_enter(&fcsm
->sm_mutex
);
960 if ((fcsm
->sm_flags
& FCSM_ATTACHED
) == 0) {
961 mutex_exit(&fcsm
->sm_mutex
);
962 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
963 "port_detach: port is not attached");
964 mutex_enter(&fcsm_global_mutex
);
965 fcsm_num_detaching
--;
966 mutex_exit(&fcsm_global_mutex
);
969 mutex_exit(&fcsm
->sm_mutex
);
972 * If fcsm has been detached, then all instance has already been
973 * detached or are being detached. So succeed this detach.
979 case FC_CMD_POWER_DOWN
:
983 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
984 "port_detach: port unknown cmd 0x%x", cmd
));
985 mutex_enter(&fcsm_global_mutex
);
986 fcsm_num_detaching
--;
987 mutex_exit(&fcsm_global_mutex
);
991 if (fcsm_handle_port_detach(pinfo
, fcsm
, cmd
) == DDI_SUCCESS
) {
995 mutex_enter(&fcsm_global_mutex
);
996 fcsm_num_detaching
--;
997 mutex_exit(&fcsm_global_mutex
);
999 /* If it was a detach, then fcsm state structure no longer exists */
1000 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1001 "port_detach: end. cmd 0x%x rval 0x%x", cmd
, rval
));
1007 fcsm_handle_port_detach(fc_ulp_port_info_t
*pinfo
, fcsm_t
*fcsm
,
1008 fc_detach_cmd_t cmd
)
1013 char pathname
[MAXPATHLEN
];
1017 * If port is already powered down OR suspended and there is nothing
1018 * else to do then just return.
1019 * Otherwise, set the flag, so that no more new activity will be
1020 * initiated on this port.
1022 mutex_enter(&fcsm
->sm_mutex
);
1026 flag
= FCSM_DETACHING
;
1029 case FC_CMD_SUSPEND
:
1030 case FC_CMD_POWER_DOWN
:
1031 ((cmd
== FC_CMD_SUSPEND
) ? (flag
= FCSM_SUSPENDED
) :
1032 (flag
= FCSM_POWER_DOWN
));
1033 if (fcsm
->sm_flags
&
1034 (FCSM_POWER_DOWN
| FCSM_SUSPENDED
)) {
1035 fcsm
->sm_flags
|= flag
;
1036 mutex_exit(&fcsm
->sm_mutex
);
1037 return (DDI_SUCCESS
);
1042 mutex_exit(&fcsm
->sm_mutex
);
1043 return (DDI_FAILURE
);
1046 fcsm
->sm_flags
|= flag
;
1049 * If some commands are pending OR callback in progress, then
1050 * wait for some finite amount of time for their completion.
1051 * TODO: add more checks here to check for cmd timeout, offline
1052 * timeout and other (??) threads.
1055 while ((count
++ <= 30) && (fcsm
->sm_ncmds
|| fcsm
->sm_cb_count
)) {
1056 mutex_exit(&fcsm
->sm_mutex
);
1058 mutex_enter(&fcsm
->sm_mutex
);
1060 if (fcsm
->sm_ncmds
|| fcsm
->sm_cb_count
) {
1061 fcsm
->sm_flags
&= ~flag
;
1062 mutex_exit(&fcsm
->sm_mutex
);
1063 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
1064 "port_detach: Failing suspend, port is busy");
1065 return (DDI_FAILURE
);
1067 if (flag
== FCSM_DETACHING
) {
1068 fcsm
->sm_flags
&= ~FCSM_DETACHING
;
1069 fcsm
->sm_flags
|= FCSM_DETACHED
;
1072 mutex_exit(&fcsm
->sm_mutex
);
1074 FCSM_DEBUG(SMDL_INFO
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1075 "port_detach: cmd 0x%x pathname <%s>",
1076 cmd
, ddi_pathname(pinfo
->port_dip
, pathname
)));
1078 if (cmd
== FC_CMD_DETACH
) {
1079 fcsm_cleanup_port(fcsm
);
1081 * Soft state cleanup done.
1082 * Always remember that fcsm struct doesn't exist anymore.
1085 fcsm_suspend_port(fcsm
);
1088 return (DDI_SUCCESS
);
1092 fcsm_suspend_port(fcsm_t
*fcsm
)
1094 mutex_enter(&fcsm
->sm_mutex
);
1096 if (fcsm
->sm_offline_tid
!= NULL
) {
1099 tid
= fcsm
->sm_offline_tid
;
1100 fcsm
->sm_offline_tid
= (timeout_id_t
)NULL
;
1101 mutex_exit(&fcsm
->sm_mutex
);
1102 (void) untimeout(tid
);
1103 mutex_enter(&fcsm
->sm_mutex
);
1104 fcsm
->sm_flags
|= FCSM_RESTORE_OFFLINE_TIMEOUT
;
1107 if (fcsm
->sm_retry_tid
!= NULL
) {
1110 tid
= fcsm
->sm_retry_tid
;
1111 fcsm
->sm_retry_tid
= (timeout_id_t
)NULL
;
1112 mutex_exit(&fcsm
->sm_mutex
);
1113 (void) untimeout(tid
);
1114 mutex_enter(&fcsm
->sm_mutex
);
1115 fcsm
->sm_flags
|= FCSM_RESTORE_RETRY_TIMEOUT
;
1118 mutex_exit(&fcsm
->sm_mutex
);
1122 fcsm_resume_port(fcsm_t
*fcsm
)
1124 mutex_enter(&fcsm
->sm_mutex
);
1126 if (fcsm
->sm_flags
& FCSM_RESTORE_OFFLINE_TIMEOUT
) {
1127 fcsm
->sm_flags
&= ~FCSM_RESTORE_OFFLINE_TIMEOUT
;
1130 * If port if offline, link is not marked down and offline
1131 * timer is not already running, then restart offline timer.
1133 if (!(fcsm
->sm_flags
& FCSM_LINK_DOWN
) &&
1134 fcsm
->sm_offline_tid
== NULL
&&
1135 (fcsm
->sm_flags
& FCSM_PORT_OFFLINE
)) {
1136 fcsm
->sm_offline_tid
= timeout(fcsm_offline_timeout
,
1137 (caddr_t
)fcsm
, fcsm_offline_ticks
);
1141 if (fcsm
->sm_flags
& FCSM_RESTORE_RETRY_TIMEOUT
) {
1142 fcsm
->sm_flags
&= ~FCSM_RESTORE_RETRY_TIMEOUT
;
1145 * If retry queue is not suspended and some cmds are waiting
1146 * to be retried, then restart the retry timer
1148 if (fcsm
->sm_retry_head
&& fcsm
->sm_retry_tid
== NULL
) {
1149 fcsm
->sm_retry_tid
= timeout(fcsm_retry_timeout
,
1150 (caddr_t
)fcsm
, fcsm_retry_ticks
);
1153 mutex_exit(&fcsm
->sm_mutex
);
1157 fcsm_cleanup_port(fcsm_t
*fcsm
)
1159 fcsm_t
*curr
, *prev
;
1163 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1164 "fcsm_cleanup_port: entered"));
1167 * Kill the job thread
1169 job
= fcsm_alloc_job(KM_SLEEP
);
1170 ASSERT(job
!= NULL
);
1171 fcsm_init_job(job
, fcsm
->sm_instance
, FCSM_JOB_THREAD_SHUTDOWN
,
1172 FCSM_JOBFLAG_SYNC
, NULL
, NULL
, NULL
, NULL
);
1174 status
= fcsm_process_job(job
, 0);
1175 ASSERT(status
== FC_SUCCESS
);
1177 ASSERT(job
->job_result
== FC_SUCCESS
);
1178 fcsm_dealloc_job(job
);
1181 * We got here after ensuring the no commands are pending or active.
1182 * Therefore retry timeout thread should NOT be running.
1183 * Kill the offline timeout thread if currently running.
1185 mutex_enter(&fcsm
->sm_mutex
);
1187 ASSERT(fcsm
->sm_retry_tid
== NULL
);
1189 if (fcsm
->sm_offline_tid
!= NULL
) {
1192 tid
= fcsm
->sm_offline_tid
;
1193 fcsm
->sm_offline_tid
= (timeout_id_t
)NULL
;
1194 mutex_exit(&fcsm
->sm_mutex
);
1195 (void) untimeout(tid
);
1197 mutex_exit(&fcsm
->sm_mutex
);
1200 /* Remove from the fcsm state structure from global linked list */
1201 mutex_enter(&fcsm_global_mutex
);
1202 curr
= fcsm_port_head
;
1204 while (curr
!= fcsm
&& curr
!= NULL
) {
1206 curr
= curr
->sm_next
;
1208 ASSERT(curr
!= NULL
);
1211 fcsm_port_head
= curr
->sm_next
;
1213 prev
->sm_next
= curr
->sm_next
;
1215 mutex_exit(&fcsm_global_mutex
);
1217 if (fcsm
->sm_cmd_cache
!= NULL
) {
1218 kmem_cache_destroy(fcsm
->sm_cmd_cache
);
1220 cv_destroy(&fcsm
->sm_job_cv
);
1221 mutex_destroy(&fcsm
->sm_mutex
);
1223 /* Free the fcsm state structure */
1224 ddi_soft_state_free(fcsm_state
, fcsm
->sm_instance
);
1230 fcsm_statec_cb(opaque_t ulph
, opaque_t port_handle
, uint32_t port_state
,
1231 uint32_t port_top
, fc_portmap_t
*devlist
, uint32_t dev_cnt
,
1235 timeout_id_t offline_tid
, retry_tid
;
1237 mutex_enter(&fcsm_global_mutex
);
1238 if (fcsm_detached
) {
1239 mutex_exit(&fcsm_global_mutex
);
1243 fcsm
= ddi_get_soft_state(fcsm_state
,
1244 fc_ulp_get_port_instance(port_handle
));
1246 mutex_exit(&fcsm_global_mutex
);
1247 FCSM_DEBUG(SMDL_TRACE
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
1248 "statec_cb: instance 0x%x not found",
1249 fc_ulp_get_port_instance(port_handle
)));
1252 mutex_enter(&fcsm
->sm_mutex
);
1253 ASSERT(fcsm
->sm_instance
== fc_ulp_get_port_instance(port_handle
));
1254 if ((fcsm
->sm_flags
& FCSM_ATTACHED
) == 0) {
1255 mutex_exit(&fcsm
->sm_mutex
);
1256 mutex_exit(&fcsm_global_mutex
);
1257 FCSM_DEBUG(SMDL_TRACE
, (CE_NOTE
, SM_LOG
, fcsm
, NULL
,
1258 "statec_cb: port not attached"));
1262 ASSERT(fcsm
->sm_cb_count
>= 0);
1264 fcsm
->sm_cb_count
++;
1265 mutex_exit(&fcsm
->sm_mutex
);
1266 mutex_exit(&fcsm_global_mutex
);
1268 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1269 "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d",
1270 fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state
)), port_state
,
1271 fcsm_topology_to_str(port_top
), port_top
, dev_cnt
));
1273 fcsm_disp_devlist(fcsm
, devlist
, dev_cnt
);
1275 mutex_enter(&fcsm
->sm_mutex
);
1278 * Reset the Mgmt server Login flag, so that login is performed again.
1280 fcsm
->sm_flags
&= ~FCSM_MGMT_SERVER_LOGGED_IN
;
1282 fcsm
->sm_sid
= port_sid
;
1283 fcsm
->sm_port_top
= port_top
;
1284 fcsm
->sm_port_state
= port_state
;
1286 switch (port_state
) {
1287 case FC_STATE_OFFLINE
:
1288 case FC_STATE_RESET
:
1289 case FC_STATE_RESET_REQUESTED
:
1290 fcsm
->sm_flags
|= FCSM_PORT_OFFLINE
;
1293 case FC_STATE_ONLINE
:
1296 case FC_STATE_LIP_LBIT_SET
:
1297 fcsm
->sm_flags
&= ~FCSM_PORT_OFFLINE
;
1298 fcsm
->sm_flags
&= ~FCSM_LINK_DOWN
;
1301 case FC_STATE_NAMESERVICE
:
1302 case FC_STATE_DEVICE_CHANGE
:
1303 case FC_STATE_TARGET_PORT_RESET
:
1309 offline_tid
= retry_tid
= NULL
;
1310 if (fcsm
->sm_flags
& FCSM_PORT_OFFLINE
) {
1313 * Suspend cmd processing and start offline timeout thread.
1315 if (fcsm
->sm_offline_tid
== NULL
) {
1316 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1317 "statec_cb: schedule offline timeout thread"));
1318 fcsm
->sm_flags
|= FCSM_CMD_RETRY_Q_SUSPENDED
;
1319 /* Stop the cmd retry thread */
1320 retry_tid
= fcsm
->sm_retry_tid
;
1321 fcsm
->sm_retry_tid
= (timeout_id_t
)NULL
;
1323 fcsm
->sm_offline_tid
= timeout(fcsm_offline_timeout
,
1324 (caddr_t
)fcsm
, fcsm_offline_ticks
);
1330 * Cancel offline timeout thread and resume command processing.
1332 if (fcsm
->sm_offline_tid
) {
1333 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1334 "statec_cb: cancel offline timeout thread"));
1335 offline_tid
= fcsm
->sm_offline_tid
;
1336 fcsm
->sm_offline_tid
= (timeout_id_t
)NULL
;
1339 fcsm
->sm_flags
&= ~FCSM_CMD_RETRY_Q_SUSPENDED
;
1340 /* Start retry thread if needed */
1341 if (fcsm
->sm_retry_head
&& fcsm
->sm_retry_tid
== NULL
) {
1342 fcsm
->sm_retry_tid
= timeout(fcsm_retry_timeout
,
1343 (caddr_t
)fcsm
, fcsm_retry_ticks
);
1347 mutex_exit(&fcsm
->sm_mutex
);
1349 if (offline_tid
!= NULL
) {
1350 (void) untimeout(offline_tid
);
1353 if (retry_tid
!= NULL
) {
1354 (void) untimeout(retry_tid
);
1357 mutex_enter(&fcsm
->sm_mutex
);
1358 fcsm
->sm_cb_count
--;
1359 ASSERT(fcsm
->sm_cb_count
>= 0);
1360 mutex_exit(&fcsm
->sm_mutex
);
1365 fcsm_offline_timeout(void *handle
)
1367 fcsm_t
*fcsm
= (fcsm_t
*)handle
;
1369 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1370 "offline_timeout"));
1372 mutex_enter(&fcsm
->sm_mutex
);
1373 if (fcsm
->sm_flags
& FCSM_PORT_OFFLINE
) {
1374 fcsm
->sm_flags
|= FCSM_LINK_DOWN
;
1376 fcsm
->sm_offline_tid
= (timeout_id_t
)NULL
;
1377 fcsm
->sm_flags
&= ~FCSM_CMD_RETRY_Q_SUSPENDED
;
1379 /* Start the retry thread if needed */
1380 if (fcsm
->sm_retry_head
&& fcsm
->sm_retry_tid
== NULL
) {
1381 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1382 "offline_timeout: reschedule cmd retry thread"));
1383 ASSERT(fcsm
->sm_retry_tid
== NULL
);
1384 fcsm
->sm_retry_tid
= timeout(fcsm_retry_timeout
,
1385 (caddr_t
)fcsm
, fcsm_retry_ticks
);
1387 mutex_exit(&fcsm
->sm_mutex
);
1392 fcsm_els_cb(opaque_t ulph
, opaque_t port_handle
, fc_unsol_buf_t
*buf
,
1395 return (FC_UNCLAIMED
);
1401 fcsm_data_cb(opaque_t ulph
, opaque_t port_handle
, fc_unsol_buf_t
*buf
,
1404 return (FC_UNCLAIMED
);
1410 fcsm_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
1415 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "ioctl: start"));
1417 mutex_enter(&fcsm_global_mutex
);
1418 if (!(fcsm_flag
& FCSM_OPEN
)) {
1419 mutex_exit(&fcsm_global_mutex
);
1422 mutex_exit(&fcsm_global_mutex
);
1424 /* Allow only root to talk */
1425 if (drv_priv(credp
)) {
1426 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1427 "ioctl: end (disallowing underprivileged user)"));
1436 #ifdef _MULTI_DATAMODEL
1437 switch (ddi_model_convert_from(mode
& FMODELS
)) {
1438 case DDI_MODEL_ILP32
: {
1439 struct fcio32 fcio32
;
1441 if (status
= ddi_copyin((void *)arg
, (void *)&fcio32
,
1442 sizeof (struct fcio32
), mode
)) {
1446 fcio
.fcio_xfer
= fcio32
.fcio_xfer
;
1447 fcio
.fcio_cmd
= fcio32
.fcio_cmd
;
1448 fcio
.fcio_flags
= fcio32
.fcio_flags
;
1449 fcio
.fcio_cmd_flags
= fcio32
.fcio_cmd_flags
;
1450 fcio
.fcio_ilen
= (size_t)fcio32
.fcio_ilen
;
1451 fcio
.fcio_ibuf
= (caddr_t
)(long)fcio32
.fcio_ibuf
;
1452 fcio
.fcio_olen
= (size_t)fcio32
.fcio_olen
;
1453 fcio
.fcio_obuf
= (caddr_t
)(long)fcio32
.fcio_obuf
;
1454 fcio
.fcio_alen
= (size_t)fcio32
.fcio_alen
;
1455 fcio
.fcio_abuf
= (caddr_t
)(long)fcio32
.fcio_abuf
;
1456 fcio
.fcio_errno
= fcio32
.fcio_errno
;
1460 case DDI_MODEL_NONE
:
1461 if (status
= ddi_copyin((void *)arg
, (void *)&fcio
,
1462 sizeof (fcio_t
), mode
)) {
1467 #else /* _MULTI_DATAMODEL */
1468 if (status
= ddi_copyin((void *)arg
, (void *)&fcio
,
1469 sizeof (fcio_t
), mode
)) {
1473 #endif /* _MULTI_DATAMODEL */
1475 retval
= fcsm_fciocmd(arg
, mode
, credp
, &fcio
);
1485 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "ioctl: end"));
1491 fcsm_port_ioctl(opaque_t ulph
, opaque_t port_handle
, dev_t dev
, int cmd
,
1492 intptr_t arg
, int mode
, cred_t
*credp
, int *rval
, uint32_t claimed
)
1494 return (FC_UNCLAIMED
);
1500 fcsm_fciocmd(intptr_t arg
, int mode
, cred_t
*credp
, fcio_t
*fcio
)
1504 switch (fcio
->fcio_cmd
) {
1505 case FCSMIO_CT_CMD
: {
1507 caddr_t user_ibuf
, user_obuf
;
1508 caddr_t req_iu
, rsp_iu
, abuf
;
1509 int status
, instance
, count
;
1511 if ((fcio
->fcio_xfer
!= FCIO_XFER_RW
) ||
1512 (fcio
->fcio_ilen
== 0) || (fcio
->fcio_ibuf
== 0) ||
1513 (fcio
->fcio_olen
== 0) || (fcio
->fcio_obuf
== 0) ||
1514 (fcio
->fcio_alen
== 0) || (fcio
->fcio_abuf
== 0) ||
1515 (fcio
->fcio_flags
!= 0) || (fcio
->fcio_cmd_flags
!= 0) ||
1516 (fcio
->fcio_ilen
> FCSM_MAX_CT_SIZE
) ||
1517 (fcio
->fcio_olen
> FCSM_MAX_CT_SIZE
) ||
1518 (fcio
->fcio_alen
> MAXPATHLEN
)) {
1524 * Get the destination port for which this ioctl
1525 * is targeted. The abuf will have the fp_minor
1528 abuf
= kmem_zalloc(fcio
->fcio_alen
, KM_SLEEP
);
1529 ASSERT(abuf
!= NULL
);
1530 if (ddi_copyin(fcio
->fcio_abuf
, abuf
, fcio
->fcio_alen
, mode
)) {
1532 kmem_free(abuf
, fcio
->fcio_alen
);
1536 instance
= *((int *)abuf
);
1537 kmem_free(abuf
, fcio
->fcio_alen
);
1540 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
1541 "fciocmd: instance 0x%x, invalid instance",
1548 * We confirmed that path corresponds to our port driver
1549 * and a valid instance.
1550 * If this port instance is not yet attached, then wait
1551 * for a finite time for attach to complete
1553 fcsm
= ddi_get_soft_state(fcsm_state
, instance
);
1555 while (count
++ <= 30) {
1557 mutex_enter(&fcsm
->sm_mutex
);
1558 if (fcsm
->sm_flags
& FCSM_ATTACHED
) {
1559 mutex_exit(&fcsm
->sm_mutex
);
1562 mutex_exit(&fcsm
->sm_mutex
);
1565 FCSM_DEBUG(SMDL_TRACE
,
1566 (CE_WARN
, SM_LOG
, NULL
, NULL
,
1567 "fciocmd: instance 0x%x, "
1568 "wait for port attach", instance
));
1571 fcsm
= ddi_get_soft_state(fcsm_state
, instance
);
1574 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, NULL
, NULL
,
1575 "fciocmd: instance 0x%x, port not attached",
1581 req_iu
= kmem_zalloc(fcio
->fcio_ilen
, KM_SLEEP
);
1582 rsp_iu
= kmem_zalloc(fcio
->fcio_olen
, KM_SLEEP
);
1583 ASSERT((req_iu
!= NULL
) && (rsp_iu
!= NULL
));
1585 if (ddi_copyin(fcio
->fcio_ibuf
, req_iu
,
1586 fcio
->fcio_ilen
, mode
)) {
1588 kmem_free(req_iu
, fcio
->fcio_ilen
);
1589 kmem_free(rsp_iu
, fcio
->fcio_olen
);
1593 user_ibuf
= fcio
->fcio_ibuf
;
1594 user_obuf
= fcio
->fcio_obuf
;
1595 fcio
->fcio_ibuf
= req_iu
;
1596 fcio
->fcio_obuf
= rsp_iu
;
1598 status
= fcsm_ct_passthru(fcsm
->sm_instance
, fcio
, KM_SLEEP
,
1599 FCSM_JOBFLAG_SYNC
, NULL
);
1600 if (status
!= FC_SUCCESS
) {
1604 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1605 "fciocmd: cmd 0x%x completion status 0x%x",
1606 fcio
->fcio_cmd
, status
));
1607 fcio
->fcio_errno
= status
;
1608 fcio
->fcio_ibuf
= user_ibuf
;
1609 fcio
->fcio_obuf
= user_obuf
;
1611 if (ddi_copyout(rsp_iu
, fcio
->fcio_obuf
,
1612 fcio
->fcio_olen
, mode
)) {
1614 kmem_free(req_iu
, fcio
->fcio_ilen
);
1615 kmem_free(rsp_iu
, fcio
->fcio_olen
);
1619 kmem_free(req_iu
, fcio
->fcio_ilen
);
1620 kmem_free(rsp_iu
, fcio
->fcio_olen
);
1622 if (fcsm_fcio_copyout(fcio
, arg
, mode
)) {
1628 case FCSMIO_ADAPTER_LIST
: {
1629 fc_hba_list_t
*list
;
1632 if ((fcio
->fcio_xfer
!= FCIO_XFER_RW
) ||
1633 (fcio
->fcio_olen
== 0) || (fcio
->fcio_obuf
== 0)) {
1638 list
= kmem_zalloc(fcio
->fcio_olen
, KM_SLEEP
);
1640 if (ddi_copyin(fcio
->fcio_obuf
, list
, fcio
->fcio_olen
, mode
)) {
1644 list
->version
= FC_HBA_LIST_VERSION
;
1646 if (fcio
->fcio_olen
< MAXPATHLEN
* list
->numAdapters
) {
1651 count
= fc_ulp_get_adapter_paths((char *)list
->hbaPaths
,
1654 /* Did something go wrong? */
1655 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1656 "Error fetching adapter list."));
1658 kmem_free(list
, fcio
->fcio_olen
);
1661 /* Sucess (or short buffer) */
1662 list
->numAdapters
= count
;
1663 if (ddi_copyout(list
, fcio
->fcio_obuf
,
1664 fcio
->fcio_olen
, mode
)) {
1667 kmem_free(list
, fcio
->fcio_olen
);
1672 FCSM_DEBUG(SMDL_TRACE
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
1673 "fciocmd: unknown cmd <0x%x>", fcio
->fcio_cmd
));
1682 fcsm_fcio_copyout(fcio_t
*fcio
, intptr_t arg
, int mode
)
1686 #ifdef _MULTI_DATAMODEL
1687 switch (ddi_model_convert_from(mode
& FMODELS
)) {
1688 case DDI_MODEL_ILP32
: {
1689 struct fcio32 fcio32
;
1691 fcio32
.fcio_xfer
= fcio
->fcio_xfer
;
1692 fcio32
.fcio_cmd
= fcio
->fcio_cmd
;
1693 fcio32
.fcio_flags
= fcio
->fcio_flags
;
1694 fcio32
.fcio_cmd_flags
= fcio
->fcio_cmd_flags
;
1695 fcio32
.fcio_ilen
= fcio
->fcio_ilen
;
1696 fcio32
.fcio_ibuf
= (caddr32_t
)(long)fcio
->fcio_ibuf
;
1697 fcio32
.fcio_olen
= fcio
->fcio_olen
;
1698 fcio32
.fcio_obuf
= (caddr32_t
)(long)fcio
->fcio_obuf
;
1699 fcio32
.fcio_alen
= fcio
->fcio_alen
;
1700 fcio32
.fcio_abuf
= (caddr32_t
)(long)fcio
->fcio_abuf
;
1701 fcio32
.fcio_errno
= fcio
->fcio_errno
;
1703 status
= ddi_copyout((void *)&fcio32
, (void *)arg
,
1704 sizeof (struct fcio32
), mode
);
1707 case DDI_MODEL_NONE
:
1708 status
= ddi_copyout((void *)fcio
, (void *)arg
,
1709 sizeof (fcio_t
), mode
);
1712 #else /* _MULTI_DATAMODEL */
1713 status
= ddi_copyout((void *)fcio
, (void *)arg
, sizeof (fcio_t
), mode
);
1714 #endif /* _MULTI_DATAMODEL */
1722 fcsm_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
1724 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "open"));
1726 if (otyp
!= OTYP_CHR
) {
1727 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1728 "fcsm_open: failed. open type 0x%x for minor 0x%x is not "
1729 "OTYP_CHR", otyp
, getminor(*devp
)));
1734 * Allow anybody to open (both root and non-root users).
1735 * Previlege level checks are made on the per ioctl basis.
1737 mutex_enter(&fcsm_global_mutex
);
1738 if (flags
& FEXCL
) {
1739 if (fcsm_flag
& FCSM_OPEN
) {
1740 mutex_exit(&fcsm_global_mutex
);
1741 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1742 "fcsm_open: exclusive open of 0x%x failed",
1746 ASSERT(fcsm_flag
== FCSM_IDLE
);
1747 fcsm_flag
|= FCSM_EXCL
;
1750 if (fcsm_flag
& FCSM_EXCL
) {
1751 mutex_exit(&fcsm_global_mutex
);
1752 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1753 "fcsm_open: failed. Device minor 0x%x is in "
1754 "exclusive open mode", getminor(*devp
)));
1759 fcsm_flag
|= FCSM_OPEN
;
1760 mutex_exit(&fcsm_global_mutex
);
1767 fcsm_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
1769 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
, "close"));
1771 if (otyp
!= OTYP_CHR
) {
1772 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1773 "fcsm_close: failed. close type 0x%x for minor 0x%x is not "
1774 "OTYP_CHR", otyp
, getminor(dev
)));
1778 mutex_enter(&fcsm_global_mutex
);
1779 if ((fcsm_flag
& FCSM_OPEN
) == 0) {
1780 mutex_exit(&fcsm_global_mutex
);
1781 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
1782 "fcsm_close: failed. minor 0x%x is already closed",
1786 fcsm_flag
= FCSM_IDLE
;
1787 mutex_exit(&fcsm_global_mutex
);
1794 fcsm_disp_devlist(fcsm_t
*fcsm
, fc_portmap_t
*devlist
, uint32_t dev_cnt
)
1803 ASSERT(devlist
!= NULL
);
1804 for (i
= 0; i
< dev_cnt
; i
++) {
1806 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
1807 "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x "
1811 i
, map
->map_did
.port_id
,
1812 map
->map_pwwn
.raw_wwn
[0], map
->map_pwwn
.raw_wwn
[1],
1813 map
->map_pwwn
.raw_wwn
[2], map
->map_pwwn
.raw_wwn
[3],
1814 map
->map_pwwn
.raw_wwn
[4], map
->map_pwwn
.raw_wwn
[5],
1815 map
->map_pwwn
.raw_wwn
[6], map
->map_pwwn
.raw_wwn
[7],
1817 fcsm_dev_type_to_str(map
->map_type
), map
->map_type
,
1824 fcsm_display(int level
, int flags
, fcsm_t
*fcsm
, fc_packet_t
*pkt
,
1825 const char *fmt
, ...)
1830 buf
= kmem_zalloc(256, KM_NOSLEEP
);
1836 (void) sprintf(buf
+ strlen(buf
), "fcsm(%d): ",
1837 ddi_get_instance(fcsm
->sm_port_info
.port_dip
));
1839 (void) sprintf(buf
, "fcsm: ");
1843 (void) vsprintf(buf
+ strlen(buf
), fmt
, ap
);
1847 caddr_t state
, reason
, action
, expln
;
1849 (void) fc_ulp_pkt_error(pkt
, &state
, &reason
, &action
, &expln
);
1851 (void) sprintf(buf
+ strlen(buf
),
1852 " state: %s(0x%x); reason: %s(0x%x)",
1853 state
, pkt
->pkt_state
, reason
, pkt
->pkt_reason
);
1858 cmn_err(level
, "!%s", buf
);
1862 cmn_err(level
, "^%s", buf
);
1866 cmn_err(level
, "%s", buf
);
1870 kmem_free(buf
, 256);
1875 * Convert FC packet state to FC errno
1878 fcsm_pkt_state_to_rval(uchar_t state
, uint32_t reason
)
1882 if (state
== FC_PKT_LOCAL_RJT
&& (reason
== FC_REASON_NO_CONNECTION
||
1883 reason
== FC_REASON_LOGIN_REQUIRED
)) {
1884 return (FC_LOGINREQ
);
1885 } else if (state
== FC_PKT_PORT_OFFLINE
&&
1886 reason
== FC_REASON_LOGIN_REQUIRED
) {
1887 return (FC_LOGINREQ
);
1890 for (count
= 0; count
< sizeof (fcsm_xlat_pkt_state
) /
1891 sizeof (fcsm_xlat_pkt_state
[0]); count
++) {
1892 if (fcsm_xlat_pkt_state
[count
].xlat_state
== state
) {
1893 return (fcsm_xlat_pkt_state
[count
].xlat_rval
);
1897 return (FC_FAILURE
);
1902 * Convert port state state to descriptive string
1905 fcsm_port_state_to_str(uint32_t port_state
)
1909 for (count
= 0; count
< sizeof (fcsm_xlat_port_state
) /
1910 sizeof (fcsm_xlat_port_state
[0]); count
++) {
1911 if (fcsm_xlat_port_state
[count
].xlat_pstate
== port_state
) {
1912 return (fcsm_xlat_port_state
[count
].xlat_state_str
);
1921 * Convert port topology state to descriptive string
1924 fcsm_topology_to_str(uint32_t topology
)
1928 for (count
= 0; count
< sizeof (fcsm_xlat_topology
) /
1929 sizeof (fcsm_xlat_topology
[0]); count
++) {
1930 if (fcsm_xlat_topology
[count
].xlat_top
== topology
) {
1931 return (fcsm_xlat_topology
[count
].xlat_top_str
);
1940 * Convert port topology state to descriptive string
1943 fcsm_dev_type_to_str(uint32_t type
)
1947 for (count
= 0; count
< sizeof (fcsm_xlat_dev_type
) /
1948 sizeof (fcsm_xlat_dev_type
[0]); count
++) {
1949 if (fcsm_xlat_dev_type
[count
].xlat_type
== type
) {
1950 return (fcsm_xlat_dev_type
[count
].xlat_str
);
1958 fcsm_cmd_cache_constructor(void *buf
, void *cdarg
, int kmflags
)
1960 fcsm_cmd_t
*cmd
= (fcsm_cmd_t
*)buf
;
1961 fcsm_t
*fcsm
= (fcsm_t
*)cdarg
;
1962 int (*callback
)(caddr_t
);
1964 fc_ulp_port_info_t
*pinfo
;
1966 ASSERT(fcsm
!= NULL
&& buf
!= NULL
);
1967 callback
= (kmflags
== KM_SLEEP
) ? DDI_DMA_SLEEP
: DDI_DMA_DONTWAIT
;
1969 cmd
->cmd_fp_pkt
= &cmd
->cmd_fc_packet
;
1970 cmd
->cmd_job
= NULL
;
1971 cmd
->cmd_fcsm
= fcsm
;
1972 cmd
->cmd_dma_flags
= 0;
1974 pkt
= &cmd
->cmd_fc_packet
;
1976 pkt
->pkt_ulp_rscn_infop
= NULL
;
1977 pkt
->pkt_fca_private
= (opaque_t
)((caddr_t
)cmd
+ sizeof (fcsm_cmd_t
));
1978 pkt
->pkt_ulp_private
= (opaque_t
)cmd
;
1980 if (!(fcsm
->sm_flags
& FCSM_USING_NODMA_FCA
)) {
1981 pinfo
= &fcsm
->sm_port_info
;
1982 if (ddi_dma_alloc_handle(pinfo
->port_dip
,
1983 pinfo
->port_cmd_dma_attr
,
1984 callback
, NULL
, &pkt
->pkt_cmd_dma
) != DDI_SUCCESS
) {
1988 if (ddi_dma_alloc_handle(pinfo
->port_dip
,
1989 pinfo
->port_resp_dma_attr
,
1990 callback
, NULL
, &pkt
->pkt_resp_dma
) != DDI_SUCCESS
) {
1991 ddi_dma_free_handle(&pkt
->pkt_cmd_dma
);
1995 pkt
->pkt_cmd_dma
= NULL
;
1996 pkt
->pkt_cmd
= NULL
;
1997 pkt
->pkt_resp_dma
= NULL
;
1998 pkt
->pkt_resp
= NULL
;
2001 pkt
->pkt_cmd_acc
= pkt
->pkt_resp_acc
= NULL
;
2002 pkt
->pkt_cmd_cookie_cnt
= pkt
->pkt_resp_cookie_cnt
=
2003 pkt
->pkt_data_cookie_cnt
= 0;
2004 pkt
->pkt_cmd_cookie
= pkt
->pkt_resp_cookie
=
2005 pkt
->pkt_data_cookie
= NULL
;
2013 fcsm_cmd_cache_destructor(void *buf
, void *cdarg
)
2015 fcsm_cmd_t
*cmd
= (fcsm_cmd_t
*)buf
;
2016 fcsm_t
*fcsm
= (fcsm_t
*)cdarg
;
2019 ASSERT(fcsm
== cmd
->cmd_fcsm
);
2021 pkt
= cmd
->cmd_fp_pkt
;
2023 if (pkt
->pkt_cmd_dma
!= NULL
) {
2024 ddi_dma_free_handle(&pkt
->pkt_cmd_dma
);
2027 if (pkt
->pkt_resp_dma
!= NULL
) {
2028 ddi_dma_free_handle(&pkt
->pkt_resp_dma
);
2034 fcsm_alloc_cmd(fcsm_t
*fcsm
, uint32_t cmd_len
, uint32_t resp_len
, int sleep
)
2040 int (*callback
)(caddr_t
);
2041 ddi_dma_cookie_t pkt_cookie
;
2042 ddi_dma_cookie_t
*cp
;
2044 fc_ulp_port_info_t
*pinfo
;
2046 ASSERT(fcsm
!= NULL
);
2047 pinfo
= &fcsm
->sm_port_info
;
2049 callback
= (sleep
== KM_SLEEP
) ? DDI_DMA_SLEEP
: DDI_DMA_DONTWAIT
;
2051 cmd
= (fcsm_cmd_t
*)kmem_cache_alloc(fcsm
->sm_cmd_cache
, sleep
);
2053 FCSM_DEBUG(SMDL_ERR
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2054 "alloc_cmd: kmem_cache_alloc failed"));
2058 cmd
->cmd_retry_count
= 0;
2059 cmd
->cmd_max_retries
= 0;
2060 cmd
->cmd_retry_interval
= 0;
2061 cmd
->cmd_transport
= NULL
;
2063 ASSERT(cmd
->cmd_dma_flags
== 0);
2064 ASSERT(cmd
->cmd_fp_pkt
== &cmd
->cmd_fc_packet
);
2065 pkt
= cmd
->cmd_fp_pkt
;
2067 /* Zero out the important fc_packet fields */
2069 pkt
->pkt_datalen
= 0;
2070 pkt
->pkt_data
= NULL
;
2072 pkt
->pkt_action
= 0;
2073 pkt
->pkt_reason
= 0;
2077 * Now that pkt_pd is initialized, we can call fc_ulp_init_packet
2080 if (fc_ulp_init_packet((opaque_t
)pinfo
->port_handle
, pkt
, sleep
)
2082 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2086 if ((cmd_len
) && !(fcsm
->sm_flags
& FCSM_USING_NODMA_FCA
)) {
2087 ASSERT(pkt
->pkt_cmd_dma
!= NULL
);
2089 rval
= ddi_dma_mem_alloc(pkt
->pkt_cmd_dma
, cmd_len
,
2090 fcsm
->sm_port_info
.port_acc_attr
, DDI_DMA_CONSISTENT
,
2091 callback
, NULL
, (caddr_t
*)&pkt
->pkt_cmd
, &real_len
,
2094 if (rval
!= DDI_SUCCESS
) {
2095 (void) fc_ulp_uninit_packet(
2096 (opaque_t
)pinfo
->port_handle
, pkt
);
2097 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2098 fcsm_free_cmd_dma(cmd
);
2102 cmd
->cmd_dma_flags
|= FCSM_CF_CMD_VALID_DMA_MEM
;
2104 if (real_len
< cmd_len
) {
2105 (void) fc_ulp_uninit_packet(
2106 (opaque_t
)pinfo
->port_handle
, pkt
);
2107 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2108 fcsm_free_cmd_dma(cmd
);
2112 rval
= ddi_dma_addr_bind_handle(pkt
->pkt_cmd_dma
, NULL
,
2113 pkt
->pkt_cmd
, real_len
, DDI_DMA_WRITE
| DDI_DMA_CONSISTENT
,
2114 callback
, NULL
, &pkt_cookie
, &pkt
->pkt_cmd_cookie_cnt
);
2116 if (rval
!= DDI_DMA_MAPPED
) {
2117 (void) fc_ulp_uninit_packet(
2118 (opaque_t
)pinfo
->port_handle
, pkt
);
2119 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2120 fcsm_free_cmd_dma(cmd
);
2124 cmd
->cmd_dma_flags
|= FCSM_CF_CMD_VALID_DMA_BIND
;
2126 if (pkt
->pkt_cmd_cookie_cnt
>
2127 pinfo
->port_cmd_dma_attr
->dma_attr_sgllen
) {
2128 (void) fc_ulp_uninit_packet(
2129 (opaque_t
)pinfo
->port_handle
, pkt
);
2130 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2131 fcsm_free_cmd_dma(cmd
);
2135 ASSERT(pkt
->pkt_cmd_cookie_cnt
!= 0);
2137 cp
= pkt
->pkt_cmd_cookie
= (ddi_dma_cookie_t
*)kmem_alloc(
2138 pkt
->pkt_cmd_cookie_cnt
* sizeof (pkt_cookie
),
2142 (void) fc_ulp_uninit_packet(
2143 (opaque_t
)pinfo
->port_handle
, pkt
);
2144 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2145 fcsm_free_cmd_dma(cmd
);
2151 for (cnt
= 1; cnt
< pkt
->pkt_cmd_cookie_cnt
; cnt
++, cp
++) {
2152 ddi_dma_nextcookie(pkt
->pkt_cmd_dma
, &pkt_cookie
);
2155 } else if (cmd_len
!= 0) {
2156 pkt
->pkt_cmd
= kmem_zalloc(cmd_len
, KM_SLEEP
);
2159 if ((resp_len
) && !(fcsm
->sm_flags
& FCSM_USING_NODMA_FCA
)) {
2160 ASSERT(pkt
->pkt_resp_dma
!= NULL
);
2162 rval
= ddi_dma_mem_alloc(pkt
->pkt_resp_dma
, resp_len
,
2163 fcsm
->sm_port_info
.port_acc_attr
, DDI_DMA_CONSISTENT
,
2164 callback
, NULL
, (caddr_t
*)&pkt
->pkt_resp
, &real_len
,
2165 &pkt
->pkt_resp_acc
);
2167 if (rval
!= DDI_SUCCESS
) {
2168 (void) fc_ulp_uninit_packet(
2169 (opaque_t
)pinfo
->port_handle
, pkt
);
2170 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2171 fcsm_free_cmd_dma(cmd
);
2175 cmd
->cmd_dma_flags
|= FCSM_CF_RESP_VALID_DMA_MEM
;
2177 if (real_len
< resp_len
) {
2178 (void) fc_ulp_uninit_packet(
2179 (opaque_t
)pinfo
->port_handle
, pkt
);
2180 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2181 fcsm_free_cmd_dma(cmd
);
2185 rval
= ddi_dma_addr_bind_handle(pkt
->pkt_resp_dma
, NULL
,
2186 pkt
->pkt_resp
, real_len
, DDI_DMA_READ
| DDI_DMA_CONSISTENT
,
2187 callback
, NULL
, &pkt_cookie
, &pkt
->pkt_resp_cookie_cnt
);
2189 if (rval
!= DDI_DMA_MAPPED
) {
2190 (void) fc_ulp_uninit_packet(
2191 (opaque_t
)pinfo
->port_handle
, pkt
);
2192 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2193 fcsm_free_cmd_dma(cmd
);
2197 cmd
->cmd_dma_flags
|= FCSM_CF_RESP_VALID_DMA_BIND
;
2199 if (pkt
->pkt_resp_cookie_cnt
>
2200 pinfo
->port_resp_dma_attr
->dma_attr_sgllen
) {
2201 (void) fc_ulp_uninit_packet(
2202 (opaque_t
)pinfo
->port_handle
, pkt
);
2203 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2204 fcsm_free_cmd_dma(cmd
);
2208 ASSERT(pkt
->pkt_resp_cookie_cnt
!= 0);
2210 cp
= pkt
->pkt_resp_cookie
= (ddi_dma_cookie_t
*)kmem_alloc(
2211 pkt
->pkt_resp_cookie_cnt
* sizeof (pkt_cookie
),
2215 (void) fc_ulp_uninit_packet(
2216 (opaque_t
)pinfo
->port_handle
, pkt
);
2217 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2218 fcsm_free_cmd_dma(cmd
);
2224 for (cnt
= 1; cnt
< pkt
->pkt_resp_cookie_cnt
; cnt
++, cp
++) {
2225 ddi_dma_nextcookie(pkt
->pkt_resp_dma
, &pkt_cookie
);
2228 } else if (resp_len
!= 0) {
2229 pkt
->pkt_resp
= kmem_zalloc(resp_len
, KM_SLEEP
);
2232 pkt
->pkt_cmdlen
= cmd_len
;
2233 pkt
->pkt_rsplen
= resp_len
;
2235 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2236 "alloc_cmd: cmd 0x%p", (void *)cmd
));
2241 fcsm_free_cmd(fcsm_cmd_t
*cmd
)
2245 fcsm
= cmd
->cmd_fcsm
;
2246 ASSERT(fcsm
!= NULL
);
2248 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2249 "free_cmd: cmd 0x%p", (void *)cmd
));
2251 fcsm_free_cmd_dma(cmd
);
2253 (void) fc_ulp_uninit_packet((opaque_t
)fcsm
->sm_port_info
.port_handle
,
2255 kmem_cache_free(fcsm
->sm_cmd_cache
, (void *)cmd
);
2259 fcsm_free_cmd_dma(fcsm_cmd_t
*cmd
)
2263 pkt
= cmd
->cmd_fp_pkt
;
2264 ASSERT(pkt
!= NULL
);
2266 if (cmd
->cmd_fcsm
->sm_flags
& FCSM_USING_NODMA_FCA
) {
2268 kmem_free(pkt
->pkt_cmd
, pkt
->pkt_cmdlen
);
2269 pkt
->pkt_cmd
= NULL
;
2272 if (pkt
->pkt_resp
) {
2273 kmem_free(pkt
->pkt_resp
, pkt
->pkt_rsplen
);
2274 pkt
->pkt_resp
= NULL
;
2278 pkt
->pkt_cmdlen
= 0;
2279 pkt
->pkt_rsplen
= 0;
2280 pkt
->pkt_tran_type
= 0;
2281 pkt
->pkt_tran_flags
= 0;
2283 if (pkt
->pkt_cmd_cookie
!= NULL
) {
2284 kmem_free(pkt
->pkt_cmd_cookie
, pkt
->pkt_cmd_cookie_cnt
*
2285 sizeof (ddi_dma_cookie_t
));
2286 pkt
->pkt_cmd_cookie
= NULL
;
2289 if (pkt
->pkt_resp_cookie
!= NULL
) {
2290 kmem_free(pkt
->pkt_resp_cookie
, pkt
->pkt_resp_cookie_cnt
*
2291 sizeof (ddi_dma_cookie_t
));
2292 pkt
->pkt_resp_cookie
= NULL
;
2295 if (cmd
->cmd_dma_flags
& FCSM_CF_CMD_VALID_DMA_BIND
) {
2296 (void) ddi_dma_unbind_handle(pkt
->pkt_cmd_dma
);
2299 if (cmd
->cmd_dma_flags
& FCSM_CF_CMD_VALID_DMA_MEM
) {
2300 if (pkt
->pkt_cmd_acc
) {
2301 ddi_dma_mem_free(&pkt
->pkt_cmd_acc
);
2305 if (cmd
->cmd_dma_flags
& FCSM_CF_RESP_VALID_DMA_BIND
) {
2306 (void) ddi_dma_unbind_handle(pkt
->pkt_resp_dma
);
2309 if (cmd
->cmd_dma_flags
& FCSM_CF_RESP_VALID_DMA_MEM
) {
2310 if (pkt
->pkt_resp_acc
) {
2311 ddi_dma_mem_free(&pkt
->pkt_resp_acc
);
2315 cmd
->cmd_dma_flags
= 0;
2320 fcsm_job_cache_constructor(void *buf
, void *cdarg
, int kmflag
)
2322 fcsm_job_t
*job
= (fcsm_job_t
*)buf
;
2324 mutex_init(&job
->job_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
2325 sema_init(&job
->job_sema
, 0, NULL
, SEMA_DEFAULT
, NULL
);
2332 fcsm_job_cache_destructor(void *buf
, void *cdarg
)
2334 fcsm_job_t
*job
= (fcsm_job_t
*)buf
;
2336 sema_destroy(&job
->job_sema
);
2337 mutex_destroy(&job
->job_mutex
);
2342 fcsm_alloc_job(int sleep
)
2346 job
= (fcsm_job_t
*)kmem_cache_alloc(fcsm_job_cache
, sleep
);
2348 job
->job_code
= FCSM_JOB_NONE
;
2350 job
->job_port_instance
= -1;
2351 job
->job_result
= -1;
2352 job
->job_arg
= (opaque_t
)0;
2353 job
->job_caller_priv
= (opaque_t
)0;
2354 job
->job_comp
= NULL
;
2355 job
->job_comp_arg
= (opaque_t
)0;
2356 job
->job_priv
= NULL
;
2357 job
->job_priv_flags
= 0;
2365 fcsm_dealloc_job(fcsm_job_t
*job
)
2367 kmem_cache_free(fcsm_job_cache
, (void *)job
);
2372 fcsm_init_job(fcsm_job_t
*job
, int instance
, uint32_t command
, uint32_t flags
,
2373 opaque_t arg
, opaque_t caller_priv
,
2374 void (*comp
)(opaque_t
, fcsm_job_t
*, int), opaque_t comp_arg
)
2376 ASSERT(job
!= NULL
);
2377 job
->job_port_instance
= instance
;
2378 job
->job_code
= command
;
2379 job
->job_flags
= flags
;
2381 job
->job_caller_priv
= caller_priv
;
2382 job
->job_comp
= comp
;
2383 job
->job_comp_arg
= comp_arg
;
2384 job
->job_retry_count
= 0;
2388 fcsm_process_job(fcsm_job_t
*job
, int priority_flag
)
2393 ASSERT(job
!= NULL
);
2394 ASSERT(!MUTEX_HELD(&job
->job_mutex
));
2396 fcsm
= ddi_get_soft_state(fcsm_state
, job
->job_port_instance
);
2399 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, NULL
, NULL
,
2400 "process_job: port instance 0x%x not found",
2401 job
->job_port_instance
));
2405 mutex_enter(&job
->job_mutex
);
2406 /* Both SYNC and ASYNC flags should not be set */
2407 ASSERT(((job
->job_flags
& (FCSM_JOBFLAG_SYNC
| FCSM_JOBFLAG_ASYNC
)) ==
2408 FCSM_JOBFLAG_SYNC
) || ((job
->job_flags
&
2409 (FCSM_JOBFLAG_SYNC
| FCSM_JOBFLAG_ASYNC
)) == FCSM_JOBFLAG_ASYNC
));
2411 * Check if job is a synchronous job. We might not be able to
2412 * check it reliably after enque_job(), if job is an ASYNC job.
2414 sync
= job
->job_flags
& FCSM_JOBFLAG_SYNC
;
2415 mutex_exit(&job
->job_mutex
);
2417 /* Queue the job for processing by job thread */
2418 fcsm_enque_job(fcsm
, job
, priority_flag
);
2420 /* Wait for job completion, if it is a synchronous job */
2423 * This is a Synchronous Job. So job structure is available.
2424 * Caller is responsible for freeing it.
2426 FCSM_DEBUG(SMDL_ERR
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2427 "process_job: Waiting for sync job <%p> completion",
2429 sema_p(&job
->job_sema
);
2432 return (FC_SUCCESS
);
2436 fcsm_enque_job(fcsm_t
*fcsm
, fcsm_job_t
*job
, int priority_flag
)
2438 ASSERT(!MUTEX_HELD(&fcsm
->sm_mutex
));
2440 mutex_enter(&fcsm
->sm_mutex
);
2441 /* Queue the job at the head or tail depending on the job priority */
2442 if (priority_flag
) {
2443 FCSM_DEBUG(SMDL_INFO
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2444 "enque_job: job 0x%p is high priority", job
));
2445 /* Queue at the head */
2446 if (fcsm
->sm_job_tail
== NULL
) {
2447 ASSERT(fcsm
->sm_job_head
== NULL
);
2448 fcsm
->sm_job_head
= fcsm
->sm_job_tail
= job
;
2450 ASSERT(fcsm
->sm_job_head
!= NULL
);
2451 job
->job_next
= fcsm
->sm_job_head
;
2452 fcsm
->sm_job_head
= job
;
2455 FCSM_DEBUG(SMDL_INFO
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2456 "enque_job: job 0x%p is normal", job
));
2457 /* Queue at the tail */
2458 if (fcsm
->sm_job_tail
== NULL
) {
2459 ASSERT(fcsm
->sm_job_head
== NULL
);
2460 fcsm
->sm_job_head
= fcsm
->sm_job_tail
= job
;
2462 ASSERT(fcsm
->sm_job_head
!= NULL
);
2463 fcsm
->sm_job_tail
->job_next
= job
;
2464 fcsm
->sm_job_tail
= job
;
2466 job
->job_next
= NULL
;
2469 /* Signal the job thread to process the job */
2470 cv_signal(&fcsm
->sm_job_cv
);
2471 mutex_exit(&fcsm
->sm_mutex
);
2475 fcsm_retry_job(fcsm_t
*fcsm
, fcsm_job_t
*job
)
2478 * If it is a CT passthru job and status is login required, then
2479 * retry the job so that login can be performed again.
2480 * Ensure that this retry is performed a finite number of times,
2481 * so that a faulty fabric does not cause us to retry forever.
2484 switch (job
->job_code
) {
2485 case FCSM_JOB_CT_PASSTHRU
: {
2487 fc_ct_header_t
*ct_header
;
2489 if (job
->job_result
!= FC_LOGINREQ
) {
2494 * If it is a management server command
2495 * then Reset the Management server login flag, so that login
2496 * gets re-established.
2497 * If it is a Name server command,
2498 * then it is 'fp' responsibility to perform the login.
2500 ASSERT(job
->job_arg
!= NULL
);
2502 (fc_ct_header_t
*)((fcio_t
*)job
->job_arg
)->fcio_ibuf
;
2503 if (ct_header
->ct_fcstype
== FCSTYPE_MGMTSERVICE
) {
2504 mutex_enter(&fcsm
->sm_mutex
);
2505 fcsm
->sm_flags
&= ~FCSM_MGMT_SERVER_LOGGED_IN
;
2506 mutex_exit(&fcsm
->sm_mutex
);
2509 if (job
->job_retry_count
>= fcsm_max_job_retries
) {
2510 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2511 "retry_job: job 0x%p max retries (%d) reached",
2512 (void *)job
, job
->job_retry_count
));
2517 * Login is required again. Retry the command, so that
2518 * login will get performed again.
2520 mutex_enter(&job
->job_mutex
);
2521 job
->job_retry_count
++;
2522 jobflag
= job
->job_flags
;
2523 mutex_exit(&job
->job_mutex
);
2525 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2526 "retry_job: retry(%d) job 0x%p",
2527 job
->job_retry_count
, (void *)job
));
2529 * This job should get picked up before the
2530 * other jobs sitting in the queue.
2531 * Requeue the command at the head and then
2532 * reset the SERIALIZE flag.
2534 fcsm_enque_job(fcsm
, job
, 1);
2535 if (jobflag
& FCSM_JOBFLAG_SERIALIZE
) {
2536 mutex_enter(&fcsm
->sm_mutex
);
2537 ASSERT(fcsm
->sm_flags
& FCSM_SERIALIZE_JOBTHREAD
);
2538 fcsm
->sm_flags
&= ~FCSM_SERIALIZE_JOBTHREAD
;
2540 /* Signal the job thread to process the job */
2541 cv_signal(&fcsm
->sm_job_cv
);
2542 mutex_exit(&fcsm
->sm_mutex
);
2545 /* Command is queued for retrying */
2556 fcsm_jobdone(fcsm_job_t
*job
)
2560 fcsm
= ddi_get_soft_state(fcsm_state
, job
->job_port_instance
);
2561 ASSERT(fcsm
!= NULL
);
2563 if (job
->job_result
!= FC_SUCCESS
) {
2564 if (fcsm_retry_job(fcsm
, job
) == 0) {
2565 /* Job retried. so just return from here */
2570 if (job
->job_comp
) {
2571 job
->job_comp(job
->job_comp_arg
, job
, job
->job_result
);
2574 mutex_enter(&job
->job_mutex
);
2575 if (job
->job_flags
& FCSM_JOBFLAG_SERIALIZE
) {
2576 mutex_exit(&job
->job_mutex
);
2577 mutex_enter(&fcsm
->sm_mutex
);
2578 ASSERT(fcsm
->sm_flags
& FCSM_SERIALIZE_JOBTHREAD
);
2579 fcsm
->sm_flags
&= ~FCSM_SERIALIZE_JOBTHREAD
;
2581 /* Signal the job thread to process the job */
2582 cv_signal(&fcsm
->sm_job_cv
);
2583 mutex_exit(&fcsm
->sm_mutex
);
2584 mutex_enter(&job
->job_mutex
);
2587 if (job
->job_flags
& FCSM_JOBFLAG_SYNC
) {
2588 mutex_exit(&job
->job_mutex
);
2589 sema_v(&job
->job_sema
);
2591 mutex_exit(&job
->job_mutex
);
2592 /* Async job, free the job structure */
2593 fcsm_dealloc_job(job
);
2598 fcsm_deque_job(fcsm_t
*fcsm
)
2602 ASSERT(MUTEX_HELD(&fcsm
->sm_mutex
));
2604 if (fcsm
->sm_job_head
== NULL
) {
2605 ASSERT(fcsm
->sm_job_tail
== NULL
);
2608 ASSERT(fcsm
->sm_job_tail
!= NULL
);
2609 job
= fcsm
->sm_job_head
;
2610 if (job
->job_next
== NULL
) {
2611 ASSERT(fcsm
->sm_job_tail
== job
);
2612 fcsm
->sm_job_tail
= NULL
;
2614 fcsm
->sm_job_head
= job
->job_next
;
2615 job
->job_next
= NULL
;
2622 /* Dedicated per port thread to process various commands */
2624 fcsm_job_thread(fcsm_t
*fcsm
)
2628 ASSERT(fcsm
!= NULL
);
2630 CALLB_CPR_INIT(&fcsm
->sm_cpr_info
, &fcsm
->sm_mutex
,
2631 callb_generic_cpr
, "fcsm_job_thread");
2632 #endif /* __lock_lint */
2635 mutex_enter(&fcsm
->sm_mutex
);
2637 while (fcsm
->sm_job_head
== NULL
||
2638 fcsm
->sm_flags
& FCSM_SERIALIZE_JOBTHREAD
) {
2639 CALLB_CPR_SAFE_BEGIN(&fcsm
->sm_cpr_info
);
2640 cv_wait(&fcsm
->sm_job_cv
, &fcsm
->sm_mutex
);
2641 CALLB_CPR_SAFE_END(&fcsm
->sm_cpr_info
, &fcsm
->sm_mutex
);
2644 job
= fcsm_deque_job(fcsm
);
2646 mutex_exit(&fcsm
->sm_mutex
);
2648 mutex_enter(&job
->job_mutex
);
2649 if (job
->job_flags
& FCSM_JOBFLAG_SERIALIZE
) {
2650 mutex_exit(&job
->job_mutex
);
2652 mutex_enter(&fcsm
->sm_mutex
);
2653 ASSERT(!(fcsm
->sm_flags
& FCSM_SERIALIZE_JOBTHREAD
));
2654 fcsm
->sm_flags
|= FCSM_SERIALIZE_JOBTHREAD
;
2655 mutex_exit(&fcsm
->sm_mutex
);
2657 mutex_exit(&job
->job_mutex
);
2660 ASSERT(fcsm
->sm_instance
== job
->job_port_instance
);
2662 switch (job
->job_code
) {
2664 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
2665 "job_thread: uninitialized job code");
2666 job
->job_result
= FC_FAILURE
;
2670 case FCSM_JOB_THREAD_SHUTDOWN
:
2671 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2672 "job_thread: job code <JOB PORT SHUTDOWN>"));
2675 * There should not be any pending jobs, when this
2678 mutex_enter(&fcsm
->sm_mutex
);
2679 ASSERT(fcsm
->sm_job_head
== NULL
);
2680 ASSERT(fcsm
->sm_job_tail
== NULL
);
2681 ASSERT(fcsm
->sm_retry_head
== NULL
);
2682 ASSERT(fcsm
->sm_retry_tail
== NULL
);
2683 job
->job_result
= FC_SUCCESS
;
2685 CALLB_CPR_EXIT(&fcsm
->sm_cpr_info
);
2687 /* CPR_EXIT has also dropped the fcsm->sm_mutex */
2694 case FCSM_JOB_LOGIN_NAME_SERVER
:
2695 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2696 "job_thread: job code <LOGIN_NAME_SERVER>"));
2697 job
->job_result
= FC_SUCCESS
;
2701 case FCSM_JOB_LOGIN_MGMT_SERVER
:
2702 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2703 "job_thread: job code <LOGIN_MGMT_SERVER>"));
2704 fcsm_job_login_mgmt_server(job
);
2707 case FCSM_JOB_CT_PASSTHRU
:
2708 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2709 "job_thread: job code <CT_PASSTHRU>"));
2710 fcsm_job_ct_passthru(job
);
2714 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2715 "job_thread: job code <UNKNOWN>"));
2716 job
->job_result
= FC_FAILURE
;
2727 fcsm_ct_init(fcsm_t
*fcsm
, fcsm_cmd_t
*cmd
, fc_ct_aiu_t
*req_iu
, size_t req_len
,
2728 void (*comp_func
)())
2732 pkt
= cmd
->cmd_fp_pkt
;
2733 ASSERT(pkt
!= NULL
);
2735 ASSERT(req_iu
->aiu_header
.ct_fcstype
== FCSTYPE_MGMTSERVICE
||
2736 (req_iu
->aiu_header
.ct_fcstype
== FCSTYPE_DIRECTORY
&&
2737 req_iu
->aiu_header
.ct_fcssubtype
== FCSSUB_DS_NAME_SERVER
));
2740 /* Set the pkt d_id properly */
2741 if (req_iu
->aiu_header
.ct_fcstype
== FCSTYPE_MGMTSERVICE
) {
2742 pkt
->pkt_cmd_fhdr
.d_id
= FS_MANAGEMENT_SERVER
;
2744 pkt
->pkt_cmd_fhdr
.d_id
= FS_NAME_SERVER
;
2747 pkt
->pkt_cmd_fhdr
.r_ctl
= R_CTL_UNSOL_CONTROL
;
2748 pkt
->pkt_cmd_fhdr
.rsvd
= 0;
2749 pkt
->pkt_cmd_fhdr
.s_id
= fcsm
->sm_sid
;
2750 pkt
->pkt_cmd_fhdr
.type
= FC_TYPE_FC_SERVICES
;
2751 pkt
->pkt_cmd_fhdr
.f_ctl
= F_CTL_SEQ_INITIATIVE
|
2752 F_CTL_FIRST_SEQ
| F_CTL_END_SEQ
;
2753 pkt
->pkt_cmd_fhdr
.seq_id
= 0;
2754 pkt
->pkt_cmd_fhdr
.df_ctl
= 0;
2755 pkt
->pkt_cmd_fhdr
.seq_cnt
= 0;
2756 pkt
->pkt_cmd_fhdr
.ox_id
= 0xffff;
2757 pkt
->pkt_cmd_fhdr
.rx_id
= 0xffff;
2758 pkt
->pkt_cmd_fhdr
.ro
= 0;
2760 pkt
->pkt_timeout
= FCSM_MS_TIMEOUT
;
2761 pkt
->pkt_comp
= comp_func
;
2763 FCSM_REP_WR(pkt
->pkt_cmd_acc
, req_iu
, pkt
->pkt_cmd
, req_len
);
2765 cmd
->cmd_transport
= fc_ulp_transport
;
2769 fcsm_ct_intr(fcsm_cmd_t
*cmd
)
2776 pkt
= cmd
->cmd_fp_pkt
;
2778 ASSERT(job
!= NULL
);
2780 fcio
= job
->job_arg
;
2781 ASSERT(fcio
!= NULL
);
2783 if (pkt
->pkt_state
!= FC_PKT_SUCCESS
) {
2784 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, cmd
->cmd_fcsm
, pkt
,
2785 "ct_intr: CT command <0x%x> to did 0x%x failed",
2786 ((fc_ct_aiu_t
*)fcio
->fcio_ibuf
)->aiu_header
.ct_cmdrsp
,
2787 pkt
->pkt_cmd_fhdr
.d_id
));
2789 /* Get the CT response payload */
2790 fcsm
= cmd
->cmd_fcsm
;
2791 FCSM_REP_RD(pkt
->pkt_resp_acc
, fcio
->fcio_obuf
,
2792 pkt
->pkt_resp
, fcio
->fcio_olen
);
2796 fcsm_pkt_state_to_rval(pkt
->pkt_state
, pkt
->pkt_reason
);
2805 fcsm_job_ct_passthru(fcsm_job_t
*job
)
2811 fc_ct_header_t
*ct_header
;
2813 ASSERT(job
!= NULL
);
2814 ASSERT(job
->job_port_instance
!= -1);
2816 job
->job_result
= FC_FAILURE
;
2817 fcsm
= ddi_get_soft_state(fcsm_state
, job
->job_port_instance
);
2824 * Process the CT Passthru job only if port is attached
2827 if (!FC_TOP_EXTERNAL(fcsm
->sm_port_top
)) {
2828 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2829 "job_ct_passthru: end (non-fabric port)"));
2830 job
->job_result
= FC_BADDEV
;
2835 fcio
= job
->job_arg
;
2836 ASSERT(fcio
!= NULL
);
2839 * If it is NOT a Management Seriver (MS) or Name Server (NS) command
2840 * then complete the command with failure.
2842 ct_header
= (fc_ct_header_t
*)fcio
->fcio_ibuf
;
2845 * According to libHBAAPI spec, CT header from libHBAAPI would always
2846 * be big endian, so we must swap CT header before continue in little
2849 mutex_enter(&job
->job_mutex
);
2850 if (!(job
->job_flags
& FCSM_JOBFLAG_CTHEADER_BE
)) {
2851 job
->job_flags
|= FCSM_JOBFLAG_CTHEADER_BE
;
2852 *((uint32_t *)((uint32_t *)ct_header
+ 0)) =
2853 BE_32(*((uint32_t *)((uint32_t *)ct_header
+ 0)));
2854 *((uint32_t *)((uint32_t *)ct_header
+ 1)) =
2855 BE_32(*((uint32_t *)((uint32_t *)ct_header
+ 1)));
2856 *((uint32_t *)((uint32_t *)ct_header
+ 2)) =
2857 BE_32(*((uint32_t *)((uint32_t *)ct_header
+ 2)));
2858 *((uint32_t *)((uint32_t *)ct_header
+ 3)) =
2859 BE_32(*((uint32_t *)((uint32_t *)ct_header
+ 3)));
2861 mutex_exit(&job
->job_mutex
);
2863 if (ct_header
->ct_fcstype
== FCSTYPE_MGMTSERVICE
) {
2864 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2865 "job_ct_passthru: Management Server Cmd"));
2866 } else if (ct_header
->ct_fcstype
== FCSTYPE_DIRECTORY
) {
2867 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2868 "job_ct_passthru: Name Server Cmd"));
2870 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2871 "job_ct_passthru: Unsupported Destination "
2872 "gs_type <0x%x> gs_subtype <0x%x>",
2873 ct_header
->ct_fcstype
, ct_header
->ct_fcssubtype
));
2876 if (ct_header
->ct_fcstype
!= FCSTYPE_MGMTSERVICE
&&
2877 (ct_header
->ct_fcstype
!= FCSTYPE_DIRECTORY
||
2878 ct_header
->ct_fcssubtype
!= FCSSUB_DS_NAME_SERVER
)) {
2879 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2880 "job_ct_passthru: end (Not a Name Server OR "
2881 "Mgmt Server Cmd)"));
2882 job
->job_result
= FC_BADCMD
;
2888 * If it is an MS command and we are not logged in to the management
2889 * server, then start the login and requeue the command.
2890 * If login to management server is in progress, then reque the
2891 * command to wait for login to complete.
2893 mutex_enter(&fcsm
->sm_mutex
);
2894 if ((ct_header
->ct_fcstype
== FCSTYPE_MGMTSERVICE
) &&
2895 !(fcsm
->sm_flags
& FCSM_MGMT_SERVER_LOGGED_IN
)) {
2896 mutex_exit(&fcsm
->sm_mutex
);
2897 if (fcsm_login_and_process_job(fcsm
, job
) != FC_SUCCESS
) {
2898 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2899 "job_ct_passthru: perform login failed"));
2900 job
->job_result
= FC_FAILURE
;
2905 mutex_exit(&fcsm
->sm_mutex
);
2908 * We are already logged in to the management server.
2909 * Issue the CT Passthru command
2911 cmd
= fcsm_alloc_cmd(fcsm
, fcio
->fcio_ilen
, fcio
->fcio_olen
, KM_SLEEP
);
2913 job
->job_result
= FC_NOMEM
;
2918 FCSM_INIT_CMD(cmd
, job
, FC_TRAN_INTR
| FC_TRAN_CLASS3
, FC_PKT_EXCHANGE
,
2919 fcsm_max_cmd_retries
, fcsm_ct_intr
);
2921 fcsm_ct_init(fcsm
, cmd
, (fc_ct_aiu_t
*)fcio
->fcio_ibuf
, fcio
->fcio_ilen
,
2922 fcsm_pkt_common_intr
);
2924 if ((status
= fcsm_issue_cmd(cmd
)) != FC_SUCCESS
) {
2925 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, cmd
->cmd_fcsm
, NULL
,
2926 "job_ct_passthru: issue CT Passthru failed, status 0x%x",
2928 job
->job_result
= status
;
2936 fcsm_login_and_process_job(fcsm_t
*fcsm
, fcsm_job_t
*orig_job
)
2938 fcsm_job_t
*login_job
;
2943 if (orig_job
->job_code
!= FCSM_JOB_CT_PASSTHRU
) {
2944 return (FC_FAILURE
);
2947 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
2948 "login_and_process_job: start login."));
2950 mutex_enter(&fcsm
->sm_mutex
);
2951 if (fcsm
->sm_flags
& FCSM_MGMT_SERVER_LOGGED_IN
) {
2953 * Directory server login completed just now, while the
2954 * mutex was dropped. Just queue the command again for
2957 mutex_exit(&fcsm
->sm_mutex
);
2958 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2959 "login_and_process_job: got job 0x%p. login just "
2960 "completed", (void *)orig_job
));
2961 fcsm_enque_job(fcsm
, orig_job
, 0);
2962 return (FC_SUCCESS
);
2965 if (fcsm
->sm_flags
& FCSM_MGMT_SERVER_LOGIN_IN_PROG
) {
2967 * Ideally we shouldn't have come here, since login
2968 * job has the serialize flag set.
2969 * Anyway, put the command back on the queue.
2971 mutex_exit(&fcsm
->sm_mutex
);
2972 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
2973 "login_and_process_job: got job 0x%p while login to "
2974 "management server in progress", (void *)orig_job
));
2975 fcsm_enque_job(fcsm
, orig_job
, 0);
2976 return (FC_SUCCESS
);
2979 fcsm
->sm_flags
|= FCSM_MGMT_SERVER_LOGIN_IN_PROG
;
2980 mutex_exit(&fcsm
->sm_mutex
);
2982 login_job
= fcsm_alloc_job(KM_SLEEP
);
2983 ASSERT(login_job
!= NULL
);
2986 * Mark the login job as SERIALIZE, so that all other jobs will
2987 * be processed after completing the login.
2988 * Save the original job (CT Passthru job) in the caller private
2989 * field in the job structure, so that CT command can be issued
2990 * after login has completed.
2992 fcsm_init_job(login_job
, fcsm
->sm_instance
, FCSM_JOB_LOGIN_MGMT_SERVER
,
2993 FCSM_JOBFLAG_ASYNC
| FCSM_JOBFLAG_SERIALIZE
,
2994 (opaque_t
)NULL
, (opaque_t
)orig_job
, fcsm_login_ms_comp
, NULL
);
2995 orig_job
->job_priv
= (void *)login_job
;
2998 status
= fcsm_process_job(login_job
, 1);
2999 ASSERT(status
== FC_SUCCESS
);
3001 (void) fcsm_process_job(login_job
, 1);
3003 return (FC_SUCCESS
);
3009 fcsm_login_ms_comp(opaque_t comp_arg
, fcsm_job_t
*login_job
, int result
)
3012 fcsm_job_t
*orig_job
;
3014 ASSERT(login_job
!= NULL
);
3016 orig_job
= (fcsm_job_t
*)login_job
->job_caller_priv
;
3018 ASSERT(orig_job
!= NULL
);
3019 ASSERT(orig_job
->job_priv
== (void *)login_job
);
3020 orig_job
->job_priv
= NULL
;
3022 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
3023 "login_ms_comp: result 0x%x", login_job
->job_result
));
3025 /* Set the login flag in the per port fcsm structure */
3026 ASSERT(login_job
->job_port_instance
== orig_job
->job_port_instance
);
3027 fcsm
= ddi_get_soft_state(fcsm_state
, login_job
->job_port_instance
);
3028 ASSERT(fcsm
!= NULL
);
3030 mutex_enter(&fcsm
->sm_mutex
);
3031 ASSERT((fcsm
->sm_flags
& FCSM_MGMT_SERVER_LOGGED_IN
) == 0);
3032 ASSERT(fcsm
->sm_flags
& FCSM_MGMT_SERVER_LOGIN_IN_PROG
);
3033 fcsm
->sm_flags
&= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG
;
3034 if (login_job
->job_result
!= FC_SUCCESS
) {
3038 * Login failed. Complete the original job with FC_LOGINREQ
3039 * status. Retry of that job will cause login to be
3042 mutex_exit(&fcsm
->sm_mutex
);
3043 orig_job
->job_result
= FC_LOGINREQ
;
3044 fcsm_jobdone(orig_job
);
3046 (void) fc_ulp_error(login_job
->job_result
, &msg
);
3047 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, NULL
,
3048 "login_ms_comp: Management server login failed: <%s>", msg
);
3051 fcsm
->sm_flags
|= FCSM_MGMT_SERVER_LOGGED_IN
;
3052 mutex_exit(&fcsm
->sm_mutex
);
3055 * Queue the original job at the head of the queue for processing.
3057 fcsm_enque_job(fcsm
, orig_job
, 1);
3062 fcsm_els_init(fcsm_cmd_t
*cmd
, uint32_t d_id
)
3067 fcsm
= cmd
->cmd_fcsm
;
3068 pkt
= cmd
->cmd_fp_pkt
;
3069 ASSERT(fcsm
!= NULL
&& pkt
!= NULL
);
3071 pkt
->pkt_cmd_fhdr
.r_ctl
= R_CTL_ELS_REQ
;
3072 pkt
->pkt_cmd_fhdr
.d_id
= d_id
;
3073 pkt
->pkt_cmd_fhdr
.rsvd
= 0;
3074 pkt
->pkt_cmd_fhdr
.s_id
= fcsm
->sm_sid
;
3075 pkt
->pkt_cmd_fhdr
.type
= FC_TYPE_EXTENDED_LS
;
3076 pkt
->pkt_cmd_fhdr
.f_ctl
= F_CTL_SEQ_INITIATIVE
| F_CTL_FIRST_SEQ
;
3077 pkt
->pkt_cmd_fhdr
.seq_id
= 0;
3078 pkt
->pkt_cmd_fhdr
.df_ctl
= 0;
3079 pkt
->pkt_cmd_fhdr
.seq_cnt
= 0;
3080 pkt
->pkt_cmd_fhdr
.ox_id
= 0xffff;
3081 pkt
->pkt_cmd_fhdr
.rx_id
= 0xffff;
3082 pkt
->pkt_cmd_fhdr
.ro
= 0;
3084 pkt
->pkt_timeout
= FCSM_ELS_TIMEOUT
;
3089 fcsm_xlogi_init(fcsm_t
*fcsm
, fcsm_cmd_t
*cmd
, uint32_t d_id
,
3090 void (*comp_func
)(), uchar_t ls_code
)
3094 la_els_logi_t
*login_params
;
3097 login_params
= (la_els_logi_t
*)
3098 kmem_zalloc(sizeof (la_els_logi_t
), KM_SLEEP
);
3099 if (login_params
== NULL
) {
3103 status
= fc_ulp_get_port_login_params(fcsm
->sm_port_info
.port_handle
,
3105 if (status
!= FC_SUCCESS
) {
3106 kmem_free(login_params
, sizeof (la_els_logi_t
));
3110 pkt
= cmd
->cmd_fp_pkt
;
3112 fcsm_els_init(cmd
, d_id
);
3113 pkt
->pkt_comp
= comp_func
;
3115 payload
.ls_code
= ls_code
;
3118 FCSM_REP_WR(pkt
->pkt_cmd_acc
, login_params
,
3119 pkt
->pkt_cmd
, sizeof (la_els_logi_t
));
3120 FCSM_REP_WR(pkt
->pkt_cmd_acc
, &payload
,
3121 pkt
->pkt_cmd
, sizeof (payload
));
3123 cmd
->cmd_transport
= fc_ulp_issue_els
;
3125 kmem_free(login_params
, sizeof (la_els_logi_t
));
3127 return (FC_SUCCESS
);
3131 fcsm_xlogi_intr(fcsm_cmd_t
*cmd
)
3137 pkt
= cmd
->cmd_fp_pkt
;
3139 ASSERT(job
!= NULL
);
3141 fcsm
= cmd
->cmd_fcsm
;
3142 ASSERT(fcsm
!= NULL
);
3144 if (pkt
->pkt_state
!= FC_PKT_SUCCESS
) {
3145 fcsm_display(CE_WARN
, SM_LOG
, fcsm
, pkt
,
3146 "xlogi_intr: login to DID 0x%x failed",
3147 pkt
->pkt_cmd_fhdr
.d_id
);
3149 /* Get the Login parameters of the Management Server */
3150 FCSM_REP_RD(pkt
->pkt_resp_acc
, &fcsm
->sm_ms_service_params
,
3151 pkt
->pkt_resp
, sizeof (la_els_logi_t
));
3155 fcsm_pkt_state_to_rval(pkt
->pkt_state
, pkt
->pkt_reason
);
3163 fcsm_job_login_mgmt_server(fcsm_job_t
*job
)
3169 ASSERT(job
!= NULL
);
3170 ASSERT(job
->job_port_instance
!= -1);
3172 fcsm
= ddi_get_soft_state(fcsm_state
, job
->job_port_instance
);
3174 job
->job_result
= FC_NOMEM
;
3180 * Issue the Login command to the management server.
3182 cmd
= fcsm_alloc_cmd(fcsm
, sizeof (la_els_logi_t
),
3183 sizeof (la_els_logi_t
), KM_SLEEP
);
3185 job
->job_result
= FC_NOMEM
;
3190 FCSM_INIT_CMD(cmd
, job
, FC_TRAN_INTR
| FC_TRAN_CLASS3
, FC_PKT_EXCHANGE
,
3191 fcsm_max_cmd_retries
, fcsm_xlogi_intr
);
3193 status
= fcsm_xlogi_init(fcsm
, cmd
, FS_MANAGEMENT_SERVER
,
3194 fcsm_pkt_common_intr
, LA_ELS_PLOGI
);
3196 if (status
!= FC_SUCCESS
) {
3197 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
3198 "job_login_mgmt_server: plogi init failed. status 0x%x",
3200 job
->job_result
= status
;
3206 if ((status
= fcsm_issue_cmd(cmd
)) != FC_SUCCESS
) {
3207 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, cmd
->cmd_fcsm
, NULL
,
3208 "job_ct_passthru: issue login cmd failed, status 0x%x",
3210 job
->job_result
= status
;
3219 fcsm_ct_passthru(int instance
, fcio_t
*fcio
, int sleep
, int job_flags
,
3220 void (*func
)(fcio_t
*))
3225 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
3226 "ct_passthru: instance 0x%x fcio 0x%p", instance
, fcio
));
3227 job
= fcsm_alloc_job(sleep
);
3228 ASSERT(sleep
== KM_NOSLEEP
|| job
!= NULL
);
3230 fcsm_init_job(job
, instance
, FCSM_JOB_CT_PASSTHRU
, job_flags
,
3231 (opaque_t
)fcio
, (opaque_t
)func
, fcsm_ct_passthru_comp
, NULL
);
3232 status
= fcsm_process_job(job
, 0);
3233 if (status
!= FC_SUCCESS
) {
3234 /* Job could not be issued. So free the job and return */
3235 fcsm_dealloc_job(job
);
3239 if (job_flags
& FCSM_JOBFLAG_SYNC
) {
3240 status
= job
->job_result
;
3241 fcsm_dealloc_job(job
);
3250 fcsm_ct_passthru_comp(opaque_t comp_arg
, fcsm_job_t
*job
, int result
)
3252 ASSERT(job
!= NULL
);
3253 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
3254 "ct_passthru_comp: result 0x%x port 0x%x",
3255 job
->job_result
, job
->job_port_instance
));
3260 fcsm_pkt_common_intr(fc_packet_t
*pkt
)
3266 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, NULL
, NULL
,
3267 "pkt_common_intr"));
3269 cmd
= (fcsm_cmd_t
*)pkt
->pkt_ulp_private
;
3270 ASSERT(cmd
!= NULL
);
3272 if (pkt
->pkt_state
== FC_PKT_SUCCESS
) {
3273 /* Command completed successfully. Just complete the command */
3278 fcsm
= cmd
->cmd_fcsm
;
3279 ASSERT(fcsm
!= NULL
);
3281 FCSM_DEBUG(SMDL_ERR
, (CE_NOTE
, SM_LOG
, cmd
->cmd_fcsm
, pkt
,
3282 "fc packet to DID 0x%x failed for pkt 0x%p",
3283 pkt
->pkt_cmd_fhdr
.d_id
, pkt
));
3285 mutex_enter(&fcsm
->sm_mutex
);
3286 if (fcsm
->sm_flags
& FCSM_LINK_DOWN
) {
3288 * No need to retry the command. The link previously
3289 * suffered an offline timeout.
3291 mutex_exit(&fcsm
->sm_mutex
);
3292 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, cmd
->cmd_fcsm
, NULL
,
3293 "pkt_common_intr: end. Link is down"));
3297 mutex_exit(&fcsm
->sm_mutex
);
3299 jobstatus
= fcsm_pkt_state_to_rval(pkt
->pkt_state
, pkt
->pkt_reason
);
3300 if (jobstatus
== FC_LOGINREQ
) {
3302 * Login to the destination is required. No need to
3303 * retry this cmd again.
3305 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, cmd
->cmd_fcsm
, NULL
,
3306 "pkt_common_intr: end. LOGIN required"));
3311 switch (pkt
->pkt_state
) {
3312 case FC_PKT_PORT_OFFLINE
:
3313 case FC_PKT_LOCAL_RJT
:
3314 case FC_PKT_TIMEOUT
: {
3317 pkt_state
= pkt
->pkt_state
;
3318 cmd
->cmd_retry_interval
= fcsm_retry_interval
;
3319 if (fcsm_retry_cmd(cmd
) != 0) {
3320 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
,
3321 cmd
->cmd_fcsm
, NULL
,
3322 "common_intr: max retries(%d) reached, status 0x%x",
3323 cmd
->cmd_retry_count
));
3326 * Restore the pkt_state to the actual failure status
3327 * received at the time of pkt completion.
3329 pkt
->pkt_state
= pkt_state
;
3330 pkt
->pkt_reason
= 0;
3333 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
,
3334 cmd
->cmd_fcsm
, NULL
,
3335 "pkt_common_intr: retry(%d) on pkt state (0x%x)",
3336 cmd
->cmd_retry_count
, pkt_state
));
3347 fcsm_issue_cmd(fcsm_cmd_t
*cmd
)
3353 pkt
= cmd
->cmd_fp_pkt
;
3354 fcsm
= cmd
->cmd_fcsm
;
3356 /* Explicitly invalidate this field till fcsm decides to use it */
3357 pkt
->pkt_ulp_rscn_infop
= NULL
;
3359 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3360 "issue_cmd: entry"));
3362 ASSERT(!MUTEX_HELD(&fcsm
->sm_mutex
));
3363 mutex_enter(&fcsm
->sm_mutex
);
3364 if (fcsm
->sm_flags
& FCSM_LINK_DOWN
) {
3366 * Update the pkt_state/pkt_reason appropriately.
3367 * Caller of this function can decide whether to call
3368 * 'pkt->pkt_comp' or use the 'status' returned by this func.
3370 mutex_exit(&fcsm
->sm_mutex
);
3371 pkt
->pkt_state
= FC_PKT_PORT_OFFLINE
;
3372 pkt
->pkt_reason
= FC_REASON_OFFLINE
;
3373 return (FC_OFFLINE
);
3375 mutex_exit(&fcsm
->sm_mutex
);
3377 ASSERT(cmd
->cmd_transport
!= NULL
);
3378 status
= cmd
->cmd_transport(fcsm
->sm_port_info
.port_handle
, pkt
);
3379 if (status
!= FC_SUCCESS
) {
3383 * No need to retry. Return the cause of failure.
3384 * Also update the pkt_state/pkt_reason. Caller of
3385 * this function can decide, whether to call
3386 * 'pkt->pkt_comp' or use the 'status' code returned
3389 pkt
->pkt_state
= FC_PKT_LOCAL_RJT
;
3390 pkt
->pkt_reason
= FC_REASON_LOGIN_REQUIRED
;
3393 case FC_DEVICE_BUSY_NEW_RSCN
:
3395 * There was a newer RSCN than what fcsm knows about.
3396 * So, just retry again
3398 cmd
->cmd_retry_count
= 0;
3401 case FC_STATEC_BUSY
:
3403 * TODO: set flag, so that command is retried after
3404 * port is back online.
3405 * FALL Through for now.
3410 case FC_DEVICE_BUSY
:
3411 cmd
->cmd_retry_interval
= fcsm_retry_interval
;
3412 if (fcsm_retry_cmd(cmd
) != 0) {
3413 FCSM_DEBUG(SMDL_TRACE
,
3414 (CE_WARN
, SM_LOG
, fcsm
, NULL
,
3415 "issue_cmd: max retries (%d) reached",
3416 cmd
->cmd_retry_count
));
3419 * status variable is not changed here.
3420 * Return the cause of the original
3421 * cmd_transport failure.
3422 * Update the pkt_state/pkt_reason. Caller
3423 * of this function can decide whether to
3424 * call 'pkt->pkt_comp' or use the 'status'
3425 * code returned by this function.
3427 pkt
->pkt_state
= FC_PKT_TRAN_BSY
;
3428 pkt
->pkt_reason
= 0;
3430 FCSM_DEBUG(SMDL_TRACE
,
3431 (CE_WARN
, SM_LOG
, fcsm
, NULL
,
3432 "issue_cmd: retry (%d) on fc status (0x%x)",
3433 cmd
->cmd_retry_count
, status
));
3435 status
= FC_SUCCESS
;
3440 FCSM_DEBUG(SMDL_TRACE
, (CE_WARN
, SM_LOG
, fcsm
, NULL
,
3441 "issue_cmd: failure status 0x%x", status
));
3443 pkt
->pkt_state
= FC_PKT_TRAN_ERROR
;
3444 pkt
->pkt_reason
= 0;
3456 fcsm_retry_cmd(fcsm_cmd_t
*cmd
)
3458 if (cmd
->cmd_retry_count
< cmd
->cmd_max_retries
) {
3459 cmd
->cmd_retry_count
++;
3460 fcsm_enque_cmd(cmd
->cmd_fcsm
, cmd
);
3468 fcsm_enque_cmd(fcsm_t
*fcsm
, fcsm_cmd_t
*cmd
)
3470 ASSERT(!MUTEX_HELD(&fcsm
->sm_mutex
));
3472 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
, "enque_cmd"));
3474 cmd
->cmd_next
= NULL
;
3475 mutex_enter(&fcsm
->sm_mutex
);
3476 if (fcsm
->sm_retry_tail
) {
3477 ASSERT(fcsm
->sm_retry_head
!= NULL
);
3478 fcsm
->sm_retry_tail
->cmd_next
= cmd
;
3479 fcsm
->sm_retry_tail
= cmd
;
3481 ASSERT(fcsm
->sm_retry_tail
== NULL
);
3482 fcsm
->sm_retry_head
= fcsm
->sm_retry_tail
= cmd
;
3484 /* Schedule retry thread, if not already running */
3485 if (fcsm
->sm_retry_tid
== NULL
) {
3486 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3487 "enque_cmd: schedule retry thread"));
3488 fcsm
->sm_retry_tid
= timeout(fcsm_retry_timeout
,
3489 (caddr_t
)fcsm
, fcsm_retry_ticks
);
3492 mutex_exit(&fcsm
->sm_mutex
);
3497 fcsm_deque_cmd(fcsm_t
*fcsm
)
3501 ASSERT(!MUTEX_HELD(&fcsm
->sm_mutex
));
3503 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
, "deque_cmd"));
3505 mutex_enter(&fcsm
->sm_mutex
);
3506 if (fcsm
->sm_retry_head
== NULL
) {
3507 ASSERT(fcsm
->sm_retry_tail
== NULL
);
3510 cmd
= fcsm
->sm_retry_head
;
3511 fcsm
->sm_retry_head
= cmd
->cmd_next
;
3512 if (fcsm
->sm_retry_head
== NULL
) {
3513 fcsm
->sm_retry_tail
= NULL
;
3515 cmd
->cmd_next
= NULL
;
3517 mutex_exit(&fcsm
->sm_mutex
);
3523 fcsm_retry_timeout(void *handle
)
3526 fcsm_cmd_t
*curr_tail
;
3531 fcsm
= (fcsm_t
*)handle
;
3533 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
, "retry_timeout"));
3536 * If retry cmd queue is suspended, then go away.
3537 * This retry thread will be restarted, when cmd queue resumes.
3539 mutex_enter(&fcsm
->sm_mutex
);
3540 if (fcsm
->sm_flags
& FCSM_CMD_RETRY_Q_SUSPENDED
) {
3542 * Clear the retry_tid, to indicate that this routine is not
3543 * currently being rescheduled.
3545 fcsm
->sm_retry_tid
= (timeout_id_t
)NULL
;
3546 mutex_exit(&fcsm
->sm_mutex
);
3547 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3548 "retry_timeout: end. No processing. "
3549 "Queue is currently suspended for this instance"));
3553 linkdown
= (fcsm
->sm_flags
& FCSM_LINK_DOWN
) ? 1 : 0;
3556 * Save the curr_tail, so that we only process the commands
3557 * which are in the queue at this time.
3559 curr_tail
= fcsm
->sm_retry_tail
;
3560 mutex_exit(&fcsm
->sm_mutex
);
3563 * Check for done flag before dequeing the command.
3564 * Dequeing before checking the done flag will cause a command
3567 while ((!done
) && ((cmd
= fcsm_deque_cmd(fcsm
)) != NULL
)) {
3569 if (cmd
== curr_tail
) {
3573 cmd
->cmd_retry_interval
-= fcsm_retry_ticker
;
3579 * No need to retry the command. The link has
3580 * suffered an offline timeout.
3582 pkt
= cmd
->cmd_fp_pkt
;
3583 pkt
->pkt_state
= FC_PKT_PORT_OFFLINE
;
3584 pkt
->pkt_reason
= FC_REASON_OFFLINE
;
3589 if (cmd
->cmd_retry_interval
<= 0) {
3590 /* Retry the command */
3591 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3592 "retry_timeout: issue cmd 0x%p", (void *)cmd
));
3593 if (fcsm_issue_cmd(cmd
) != FC_SUCCESS
) {
3594 cmd
->cmd_fp_pkt
->pkt_comp(cmd
->cmd_fp_pkt
);
3598 * Put the command back on the queue. Retry time
3599 * has not yet reached.
3601 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3602 "retry_timeout: queue cmd 0x%p", (void *)cmd
));
3603 fcsm_enque_cmd(fcsm
, cmd
);
3607 mutex_enter(&fcsm
->sm_mutex
);
3608 if (fcsm
->sm_retry_head
) {
3609 /* Activate timer */
3610 fcsm
->sm_retry_tid
= timeout(fcsm_retry_timeout
,
3611 (caddr_t
)fcsm
, fcsm_retry_ticks
);
3612 FCSM_DEBUG(SMDL_TRACE
, (CE_CONT
, SM_LOG
, fcsm
, NULL
,
3613 "retry_timeout: retry thread rescheduled"));
3616 * Reset the tid variable. The first thread which queues the
3617 * command, will restart the timer.
3619 fcsm
->sm_retry_tid
= (timeout_id_t
)NULL
;
3621 mutex_exit(&fcsm
->sm_mutex
);