1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * fcsm - ULP Module for Fibre Channel SAN Management
28 */
29
30 #include <sys/types.h>
31 #include <sys/file.h>
32 #include <sys/kmem.h>
33 #include <sys/scsi/scsi.h>
34 #include <sys/var.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>
39
40 /* Definitions */
41 #define FCSM_VERSION "20090729-1.28"
42 #define FCSM_NAME_VERSION "SunFC FCSM v" FCSM_VERSION
43
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;
55
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;
63
64
65
66 #ifdef DEBUG
67 uint32_t fcsm_debug = (SMDL_TRACE | SMDL_IO |
68 SMDL_ERR | SMDL_INFO);
69 #endif
70
71
72 /* Character/Block entry points */
73 struct cb_ops fcsm_cb_ops = {
74 fcsm_open, /* open */
75 fcsm_close, /* close */
76 nodev, /* strategy */
77 nodev, /* print */
78 nodev, /* dump */
79 nodev, /* read */
80 nodev, /* write */
81 fcsm_ioctl, /* ioctl */
82 nodev, /* devmap */
83 nodev, /* mmap */
84 nodev, /* segmap */
85 nochpoll, /* poll */
86 ddi_prop_op,
87 NULL, /* streams info */
88 D_NEW | D_MP,
89 CB_REV,
90 nodev, /* aread */
91 nodev /* awrite */
92 };
93
94 struct dev_ops fcsm_ops = {
95 DEVO_REV,
96 0, /* refcnt */
97 fcsm_getinfo, /* get info */
98 nulldev, /* identify (obsolete) */
99 nulldev, /* probe (not required for self-identifying devices) */
100 fcsm_attach, /* attach */
101 fcsm_detach, /* detach */
102 nodev, /* reset */
103 &fcsm_cb_ops, /* char/block entry points structure for leaf drivers */
104 NULL, /* bus operations for nexus driver */
105 NULL /* power management */
106 };
107
108
109 struct modldrv modldrv = {
110 &mod_driverops,
111 FCSM_NAME_VERSION,
112 &fcsm_ops
113 };
114
115 struct modlinkage modlinkage = {
116 MODREV_1,
117 &modldrv,
118 NULL
119 };
120
121 static fc_ulp_modinfo_t fcsm_modinfo = {
122 &fcsm_modinfo, /* ulp_handle */
123 FCTL_ULP_MODREV_4, /* ulp_rev */
124 FC_TYPE_FC_SERVICES, /* ulp_type */
125 fcsm_name, /* ulp_name */
126 0, /* ulp_statec_mask: get all statec callbacks */
127 fcsm_port_attach, /* ulp_port_attach */
128 fcsm_port_detach, /* ulp_port_detach */
129 fcsm_port_ioctl, /* ulp_port_ioctl */
130 fcsm_els_cb, /* ulp_els_callback */
131 fcsm_data_cb, /* ulp_data_callback */
132 fcsm_statec_cb /* ulp_statec_callback */
133 };
134
135 struct fcsm_xlat_pkt_state {
136 uchar_t xlat_state;
137 int xlat_rval;
138 } fcsm_xlat_pkt_state [] = {
139 { FC_PKT_SUCCESS, FC_SUCCESS },
140 { FC_PKT_REMOTE_STOP, FC_FAILURE },
141 { FC_PKT_LOCAL_RJT, FC_TRANSPORT_ERROR },
142 { FC_PKT_NPORT_RJT, FC_PREJECT },
143 { FC_PKT_FABRIC_RJT, FC_FREJECT },
144 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY },
145 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY },
146 { FC_PKT_NPORT_BSY, FC_PBUSY },
147 { FC_PKT_FABRIC_BSY, FC_FBUSY },
148 { FC_PKT_LS_RJT, FC_PREJECT },
149 { FC_PKT_BA_RJT, FC_PREJECT },
150 { FC_PKT_TIMEOUT, FC_FAILURE },
151 { FC_PKT_FS_RJT, FC_FAILURE },
152 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR },
153 { FC_PKT_FAILURE, FC_FAILURE },
154 { FC_PKT_PORT_OFFLINE, FC_OFFLINE },
155 { FC_PKT_ELS_IN_PROGRESS, FC_FAILURE }
156 };
157
158 struct fcsm_xlat_port_state {
159 uint32_t xlat_pstate;
160 caddr_t xlat_state_str;
161 } fcsm_xlat_port_state [] = {
162 { FC_STATE_OFFLINE, "OFFLINE" },
163 { FC_STATE_ONLINE, "ONLINE" },
164 { FC_STATE_LOOP, "LOOP" },
165 { FC_STATE_NAMESERVICE, "NAMESERVICE" },
166 { FC_STATE_RESET, "RESET" },
167 { FC_STATE_RESET_REQUESTED, "RESET_REQUESTED" },
168 { FC_STATE_LIP, "LIP" },
169 { FC_STATE_LIP_LBIT_SET, "LIP_LBIT_SET" },
170 { FC_STATE_DEVICE_CHANGE, "DEVICE_CHANGE" },
171 { FC_STATE_TARGET_PORT_RESET, "TARGET_PORT_RESET" }
172 };
173
174 struct fcsm_xlat_topology {
175 uint32_t xlat_top;
176 caddr_t xlat_top_str;
177 } fcsm_xlat_topology [] = {
178 { FC_TOP_UNKNOWN, "UNKNOWN" },
179 { FC_TOP_PRIVATE_LOOP, "Private Loop" },
180 { FC_TOP_PUBLIC_LOOP, "Public Loop" },
181 { FC_TOP_FABRIC, "Fabric" },
182 { FC_TOP_PT_PT, "Point-to-Point" },
183 { FC_TOP_NO_NS, "NO_NS" }
184 };
185
186 struct fcsm_xlat_dev_type {
187 uint32_t xlat_type;
188 caddr_t xlat_str;
189 } fcsm_xlat_dev_type [] = {
190 { PORT_DEVICE_NOCHANGE, "No Change" },
191 { PORT_DEVICE_NEW, "New" },
192 { PORT_DEVICE_OLD, "Old" },
193 { PORT_DEVICE_CHANGED, "Changed" },
194 { PORT_DEVICE_DELETE, "Delete" },
195 { PORT_DEVICE_USER_LOGIN, "User Login" },
196 { PORT_DEVICE_USER_LOGOUT, "User Logout" },
197 { PORT_DEVICE_USER_CREATE, "User Create" },
198 { PORT_DEVICE_USER_DELETE, "User Delete" }
199 };
200
201 int
_init(void)202 _init(void)
203 {
204 int rval;
205
206 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_init"));
207
208 fcsm_retry_ticks = drv_usectohz(fcsm_retry_ticker * 1000 * 1000);
209 fcsm_offline_ticks = drv_usectohz(fcsm_offline_ticker * 1000 * 1000);
210
211 if (rval = ddi_soft_state_init(&fcsm_state, sizeof (fcsm_t),
212 FCSM_INIT_INSTANCES)) {
213 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
214 "_init: ddi_soft_state_init failed");
215 return (ENOMEM);
216 }
217
218 mutex_init(&fcsm_global_mutex, NULL, MUTEX_DRIVER, NULL);
219
220 fcsm_job_cache = kmem_cache_create("fcsm_job_cache",
221 sizeof (fcsm_job_t), 8, fcsm_job_cache_constructor,
222 fcsm_job_cache_destructor, NULL, NULL, NULL, 0);
223
224 if (fcsm_job_cache == NULL) {
225 mutex_destroy(&fcsm_global_mutex);
226 ddi_soft_state_fini(&fcsm_state);
227 return (ENOMEM);
228 }
229
230 /*
231 * Now call fc_ulp_add to add this ULP in the transport layer
232 * database. This will cause 'ulp_port_attach' callback function
233 * to be called.
234 */
235 rval = fc_ulp_add(&fcsm_modinfo);
236 if (rval != 0) {
237 switch (rval) {
238 case FC_ULP_SAMEMODULE:
239 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
240 "_init: FC SAN Management module is already "
241 "registered with transport layer");
242 rval = EEXIST;
243 break;
244
245 case FC_ULP_SAMETYPE:
246 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
247 "_init: Another module with same type 0x%x is "
248 "already registered with transport layer",
249 fcsm_modinfo.ulp_type);
250 rval = EEXIST;
251 break;
252
253 case FC_BADULP:
254 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
255 "_init: Please upgrade this module. Current "
256 "version 0x%x is not the most recent version",
257 fcsm_modinfo.ulp_rev);
258 rval = EIO;
259 break;
260 default:
261 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
262 "_init: fc_ulp_add failed with status 0x%x", rval);
263 rval = EIO;
264 break;
265 }
266 kmem_cache_destroy(fcsm_job_cache);
267 mutex_destroy(&fcsm_global_mutex);
268 ddi_soft_state_fini(&fcsm_state);
269 return (rval);
270 }
271
272 if ((rval = mod_install(&modlinkage)) != 0) {
273 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
274 "_init: mod_install failed with status 0x%x", rval));
275 (void) fc_ulp_remove(&fcsm_modinfo);
276 kmem_cache_destroy(fcsm_job_cache);
277 mutex_destroy(&fcsm_global_mutex);
278 ddi_soft_state_fini(&fcsm_state);
279 return (rval);
280 }
281
282 return (rval);
283 }
284
285 int
_fini(void)286 _fini(void)
287 {
288 int rval;
289 #ifdef DEBUG
290 int status;
291 #endif /* DEBUG */
292
293 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_fini"));
294
295 /*
296 * don't start cleaning up until we know that the module remove
297 * has worked -- if this works, then we know that each instance
298 * has successfully been DDI_DETACHed
299 */
300 if ((rval = mod_remove(&modlinkage)) != 0) {
301 return (rval);
302 }
303
304 #ifdef DEBUG
305 status = fc_ulp_remove(&fcsm_modinfo);
306 if (status != 0) {
307 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
308 "_fini: fc_ulp_remove failed with status 0x%x", status));
309 }
310 #else
311 (void) fc_ulp_remove(&fcsm_modinfo);
312 #endif /* DEBUG */
313
314 fcsm_detached = 0;
315
316 /*
317 * It is possible to modunload fcsm manually, which will cause
318 * a bypass of all the port_detach functionality. We may need
319 * to force that code path to be executed to properly clean up
320 * in that case.
321 */
322 fcsm_force_port_detach_all();
323
324 kmem_cache_destroy(fcsm_job_cache);
325 mutex_destroy(&fcsm_global_mutex);
326 ddi_soft_state_fini(&fcsm_state);
327
328 return (rval);
329 }
330
331
332 int
_info(struct modinfo * modinfop)333 _info(struct modinfo *modinfop)
334 {
335 return (mod_info(&modlinkage, modinfop));
336 }
337
338 /* ARGSUSED */
339 static int
fcsm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)340 fcsm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
341 {
342 int rval = DDI_FAILURE;
343
344 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
345 "attach: cmd 0x%x", cmd));
346
347 switch (cmd) {
348 case DDI_ATTACH:
349 mutex_enter(&fcsm_global_mutex);
350 if (fcsm_dip != NULL) {
351 mutex_exit(&fcsm_global_mutex);
352 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
353 "attach: duplicate attach of fcsm!!"));
354 break;
355 }
356
357 fcsm_dip = dip;
358
359 /*
360 * The detach routine cleans up all the port instances
361 * i.e. it detaches all ports.
362 * If _fini never got called after detach, then
363 * perform an fc_ulp_remove() followed by fc_ulp_add()
364 * to ensure that port_attach callbacks are called
365 * again.
366 */
367 if (fcsm_detached) {
368 int status;
369
370 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
371 "attach: rebinding to transport driver"));
372
373 mutex_exit(&fcsm_global_mutex);
374
375 (void) fc_ulp_remove(&fcsm_modinfo);
376
377 /*
378 * Reset the detached flag, so that ports can attach
379 */
380 mutex_enter(&fcsm_global_mutex);
381 fcsm_detached = 0;
382 mutex_exit(&fcsm_global_mutex);
383
384 status = fc_ulp_add(&fcsm_modinfo);
385
386 if (status != 0) {
387 /*
388 * ULP add failed. So set the
389 * detached flag again
390 */
391 mutex_enter(&fcsm_global_mutex);
392 fcsm_detached = 1;
393 mutex_exit(&fcsm_global_mutex);
394
395 switch (status) {
396 case FC_ULP_SAMEMODULE:
397 fcsm_display(CE_WARN, SM_LOG, NULL,
398 NULL, "attach: FC SAN Management "
399 "module is already "
400 "registered with transport layer");
401 break;
402
403 case FC_ULP_SAMETYPE:
404 fcsm_display(CE_WARN, SM_LOG, NULL,
405 NULL, "attach: Another module with "
406 "same type 0x%x is already "
407 "registered with transport layer",
408 fcsm_modinfo.ulp_type);
409 break;
410
411 case FC_BADULP:
412 fcsm_display(CE_WARN, SM_LOG, NULL,
413 NULL, "attach: Please upgrade this "
414 "module. Current version 0x%x is "
415 "not the most recent version",
416 fcsm_modinfo.ulp_rev);
417 break;
418 default:
419 fcsm_display(CE_WARN, SM_LOG, NULL,
420 NULL, "attach: fc_ulp_add failed "
421 "with status 0x%x", status);
422 break;
423 }
424
425 /* Return failure */
426 break;
427 }
428
429 mutex_enter(&fcsm_global_mutex);
430 }
431
432 /* Create a minor node */
433 if (ddi_create_minor_node(fcsm_dip, "fcsm", S_IFCHR,
434 NULL, DDI_PSEUDO, 0) == DDI_SUCCESS) {
435 /* Announce presence of the device */
436 mutex_exit(&fcsm_global_mutex);
437 ddi_report_dev(dip);
438 rval = DDI_SUCCESS;
439 } else {
440 fcsm_dip = NULL;
441 mutex_exit(&fcsm_global_mutex);
442 fcsm_display(CE_WARN, SM_LOG_AND_CONSOLE,
443 NULL, NULL, "attach: create minor node failed");
444 }
445 break;
446
447 case DDI_RESUME:
448 rval = DDI_SUCCESS;
449 break;
450
451 default:
452 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
453 "attach: unknown cmd 0x%x dip 0x%p", cmd, dip));
454 break;
455 }
456
457 return (rval);
458 }
459
460 /* ARGSUSED */
461 static int
fcsm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)462 fcsm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
463 {
464 int instance;
465 int rval = DDI_SUCCESS;
466
467 instance = getminor((dev_t)arg);
468
469 switch (cmd) {
470 case DDI_INFO_DEVT2INSTANCE:
471 *result = (void *)(long)instance; /* minor number is instance */
472 break;
473
474 case DDI_INFO_DEVT2DEVINFO:
475 mutex_enter(&fcsm_global_mutex);
476 *result = (void *)fcsm_dip;
477 mutex_exit(&fcsm_global_mutex);
478 break;
479
480 default:
481 rval = DDI_FAILURE;
482 break;
483 }
484
485 return (rval);
486 }
487
488
489 /* ARGSUSED */
490 static int
fcsm_port_attach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_attach_cmd_t cmd,uint32_t s_id)491 fcsm_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
492 fc_attach_cmd_t cmd, uint32_t s_id)
493 {
494 int instance;
495 int rval = FC_FAILURE;
496
497 instance = ddi_get_instance(pinfo->port_dip);
498
499 /*
500 * Set the attaching flag, so that fcsm_detach will fail, if
501 * port attach is in progress.
502 */
503 mutex_enter(&fcsm_global_mutex);
504 if (fcsm_detached) {
505 mutex_exit(&fcsm_global_mutex);
506
507 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
508 "port_attach: end. detach in progress. failing attach "
509 "instance 0x%x", instance));
510 return (((cmd == FC_CMD_POWER_UP) || (cmd == FC_CMD_RESUME)) ?
511 FC_FAILURE_SILENT : FC_FAILURE);
512 }
513
514 fcsm_num_attaching++;
515 mutex_exit(&fcsm_global_mutex);
516
517 switch (cmd) {
518 case FC_CMD_ATTACH:
519 if (fcsm_handle_port_attach(pinfo, s_id, instance)
520 != DDI_SUCCESS) {
521 ASSERT(ddi_get_soft_state(fcsm_state,
522 instance) == NULL);
523 break;
524 }
525 rval = FC_SUCCESS;
526 break;
527
528 case FC_CMD_RESUME:
529 case FC_CMD_POWER_UP: {
530 fcsm_t *fcsm;
531 char fcsm_pathname[MAXPATHLEN];
532
533 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
534 "port_attach: cmd 0x%x instance 0x%x", cmd, instance));
535
536 /* Get the soft state structure */
537 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
538 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
539 "port_attach: instance 0x%x, cmd 0x%x "
540 "get softstate failed", instance, cmd));
541 break;
542 }
543
544 ASSERT(fcsm->sm_instance == instance);
545
546 /* If this instance is not attached, then return failure */
547 mutex_enter(&fcsm->sm_mutex);
548 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
549 mutex_exit(&fcsm->sm_mutex);
550 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
551 "port_detach: port is not attached");
552 break;
553 }
554 mutex_exit(&fcsm->sm_mutex);
555
556 if (fcsm_handle_port_resume(ulph, pinfo, cmd, s_id, fcsm) !=
557 DDI_SUCCESS) {
558 break;
559 }
560
561 (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
562 fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
563 "attached to path %s", fcsm_pathname);
564 rval = FC_SUCCESS;
565 break;
566 }
567
568 default:
569 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
570 "port_attach: unknown cmd 0x%x for port 0x%x",
571 cmd, instance));
572 break;
573 }
574
575 mutex_enter(&fcsm_global_mutex);
576 fcsm_num_attaching--;
577 mutex_exit(&fcsm_global_mutex);
578 return (rval);
579 }
580
581
582 static int
fcsm_handle_port_attach(fc_ulp_port_info_t * pinfo,uint32_t s_id,int instance)583 fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance)
584 {
585 fcsm_t *fcsm;
586 kthread_t *thread;
587 char name[32];
588 char fcsm_pathname[MAXPATHLEN];
589
590 /* Allocate a soft state structure for the port */
591 if (ddi_soft_state_zalloc(fcsm_state, instance) != DDI_SUCCESS) {
592 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
593 "port_attach: instance 0x%x, soft state alloc failed",
594 instance);
595 return (DDI_FAILURE);
596 }
597
598 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
599 fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
600 "port_attach: instance 0x%x, get soft state failed",
601 instance);
602 ddi_soft_state_free(fcsm_state, instance);
603 return (DDI_FAILURE);
604 }
605
606
607 /* Initialize the mutex */
608 mutex_init(&fcsm->sm_mutex, NULL, MUTEX_DRIVER, NULL);
609 cv_init(&fcsm->sm_job_cv, NULL, CV_DRIVER, NULL);
610
611 mutex_enter(&fcsm->sm_mutex);
612 fcsm->sm_flags |= FCSM_ATTACHING;
613 fcsm->sm_sid = s_id;
614 fcsm->sm_instance = instance;
615 fcsm->sm_port_state = pinfo->port_state;
616
617 /*
618 * Make a copy of the port_information structure, since fctl
619 * uses a temporary structure.
620 */
621 fcsm->sm_port_info = *pinfo; /* Structure copy !!! */
622 mutex_exit(&fcsm->sm_mutex);
623
624
625 (void) sprintf(name, "fcsm%d_cmd_cache", fcsm->sm_instance);
626 fcsm->sm_cmd_cache = kmem_cache_create(name,
627 sizeof (fcsm_cmd_t) + pinfo->port_fca_pkt_size, 8,
628 fcsm_cmd_cache_constructor, fcsm_cmd_cache_destructor,
629 NULL, (void *)fcsm, NULL, 0);
630 if (fcsm->sm_cmd_cache == NULL) {
631 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
632 "port_attach: pkt cache create failed");
633 cv_destroy(&fcsm->sm_job_cv);
634 mutex_destroy(&fcsm->sm_mutex);
635 ddi_soft_state_free(fcsm_state, instance);
636 return (DDI_FAILURE);
637 }
638
639 thread = thread_create((caddr_t)NULL, 0, fcsm_job_thread,
640 (caddr_t)fcsm, 0, &p0, TS_RUN, v.v_maxsyspri-2);
641 if (thread == NULL) {
642 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
643 "port_attach: job thread create failed");
644 kmem_cache_destroy(fcsm->sm_cmd_cache);
645 cv_destroy(&fcsm->sm_job_cv);
646 mutex_destroy(&fcsm->sm_mutex);
647 ddi_soft_state_free(fcsm_state, instance);
648 return (DDI_FAILURE);
649 }
650
651 fcsm->sm_thread = thread;
652
653 /* Add this structure to fcsm global linked list */
654 mutex_enter(&fcsm_global_mutex);
655 if (fcsm_port_head == NULL) {
656 fcsm_port_head = fcsm;
657 } else {
658 fcsm->sm_next = fcsm_port_head;
659 fcsm_port_head = fcsm;
660 }
661 mutex_exit(&fcsm_global_mutex);
662
663 mutex_enter(&fcsm->sm_mutex);
664 fcsm->sm_flags &= ~FCSM_ATTACHING;
665 fcsm->sm_flags |= FCSM_ATTACHED;
666 fcsm->sm_port_top = pinfo->port_flags;
667 fcsm->sm_port_state = pinfo->port_state;
668 if (pinfo->port_acc_attr == NULL) {
669 /*
670 * The corresponding FCA doesn't support DMA at all
671 */
672 fcsm->sm_flags |= FCSM_USING_NODMA_FCA;
673 }
674 mutex_exit(&fcsm->sm_mutex);
675
676 (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
677 fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
678 "attached to path %s", fcsm_pathname);
679
680 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
681 "port_attach: state <%s>(0x%x) topology <%s>(0x%x)",
682 fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo->port_state)),
683 pinfo->port_state,
684 fcsm_topology_to_str(pinfo->port_flags), pinfo->port_flags));
685
686 return (DDI_SUCCESS);
687 }
688
689 static int
fcsm_handle_port_resume(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_attach_cmd_t cmd,uint32_t s_id,fcsm_t * fcsm)690 fcsm_handle_port_resume(opaque_t ulph, fc_ulp_port_info_t *pinfo,
691 fc_attach_cmd_t cmd, uint32_t s_id, fcsm_t *fcsm)
692 {
693 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
694 "port_resume: cmd 0x%x", cmd));
695
696 mutex_enter(&fcsm->sm_mutex);
697
698 switch (cmd) {
699 case FC_CMD_RESUME:
700 ASSERT(!(fcsm->sm_flags & FCSM_POWER_DOWN));
701 fcsm->sm_flags &= ~FCSM_SUSPENDED;
702 break;
703
704 case FC_CMD_POWER_UP:
705 /* If port is suspended, then no need to resume */
706 fcsm->sm_flags &= ~FCSM_POWER_DOWN;
707 if (fcsm->sm_flags & FCSM_SUSPENDED) {
708 mutex_exit(&fcsm->sm_mutex);
709 return (DDI_SUCCESS);
710 }
711 break;
712 default:
713 mutex_exit(&fcsm->sm_mutex);
714 return (DDI_FAILURE);
715 }
716
717 fcsm->sm_sid = s_id;
718
719 /*
720 * Make a copy of the new port_information structure
721 */
722 fcsm->sm_port_info = *pinfo; /* Structure copy !!! */
723 mutex_exit(&fcsm->sm_mutex);
724
725 fcsm_resume_port(fcsm);
726
727 /*
728 * Invoke state change processing.
729 * This will ensure that
730 * - offline timer is started if new port state changed to offline.
731 * - MGMT_SERVER_LOGIN flag is reset.
732 * - Port topology is updated.
733 */
734 fcsm_statec_cb(ulph, (opaque_t)pinfo->port_handle, pinfo->port_state,
735 pinfo->port_flags, NULL, 0, s_id);
736
737 return (DDI_SUCCESS);
738 }
739
740
741 /* ARGSUSED */
742 static int
fcsm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)743 fcsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
744 {
745 int rval = DDI_SUCCESS;
746
747 switch (cmd) {
748 case DDI_DETACH: {
749 fcsm_t *fcsm;
750
751 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
752 "detach: start. cmd <DETACH>", cmd));
753
754 mutex_enter(&fcsm_global_mutex);
755
756 /*
757 * If port attach/detach in progress, then wait for 5 seconds
758 * for them to complete.
759 */
760 if (fcsm_num_attaching || fcsm_num_detaching) {
761 int count;
762
763 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
764 "detach: wait for port attach/detach to complete"));
765
766 count = 0;
767 while ((count++ <= 30) &&
768 (fcsm_num_attaching || fcsm_num_detaching)) {
769 mutex_exit(&fcsm_global_mutex);
770 delay(drv_usectohz(1000000));
771 mutex_enter(&fcsm_global_mutex);
772 }
773
774 /* Port attach/detach still in prog, so fail detach */
775 if (fcsm_num_attaching || fcsm_num_detaching) {
776 mutex_exit(&fcsm_global_mutex);
777 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL,
778 NULL, "detach: Failing detach. port "
779 "attach/detach in progress"));
780 rval = DDI_FAILURE;
781 break;
782 }
783 }
784
785 if (fcsm_port_head == NULL) {
786 /* Not much do, Succeed to detach. */
787 ddi_remove_minor_node(fcsm_dip, NULL);
788 fcsm_dip = NULL;
789 fcsm_detached = 0;
790 mutex_exit(&fcsm_global_mutex);
791 break;
792 }
793
794 /*
795 * Check to see, if any ports are active.
796 * If not, then set the DETACHING flag to indicate
797 * that they are being detached.
798 */
799 fcsm = fcsm_port_head;
800 while (fcsm != NULL) {
801
802 mutex_enter(&fcsm->sm_mutex);
803 if (!(fcsm->sm_flags & FCSM_ATTACHED) ||
804 fcsm->sm_ncmds || fcsm->sm_cb_count) {
805 /* port is busy. We can't detach */
806 mutex_exit(&fcsm->sm_mutex);
807 break;
808 }
809
810 fcsm->sm_flags |= FCSM_DETACHING;
811 mutex_exit(&fcsm->sm_mutex);
812
813 fcsm = fcsm->sm_next;
814 }
815
816 /*
817 * If all ports could not be marked for detaching,
818 * then clear the flags and fail the detach.
819 * Also if a port attach is currently in progress
820 * then fail the detach.
821 */
822 if (fcsm != NULL || fcsm_num_attaching || fcsm_num_detaching) {
823 /*
824 * Some ports were busy, so can't detach.
825 * Clear the DETACHING flag and return failure
826 */
827 fcsm = fcsm_port_head;
828 while (fcsm != NULL) {
829 mutex_enter(&fcsm->sm_mutex);
830 if (fcsm->sm_flags & FCSM_DETACHING) {
831 fcsm->sm_flags &= ~FCSM_DETACHING;
832 }
833 mutex_exit(&fcsm->sm_mutex);
834
835 fcsm = fcsm->sm_next;
836 }
837 mutex_exit(&fcsm_global_mutex);
838 return (DDI_FAILURE);
839 } else {
840 fcsm_detached = 1;
841 /*
842 * Mark all the detaching ports as detached, as we
843 * will be detaching them
844 */
845 fcsm = fcsm_port_head;
846 while (fcsm != NULL) {
847 mutex_enter(&fcsm->sm_mutex);
848 fcsm->sm_flags &= ~FCSM_DETACHING;
849 fcsm->sm_flags |= FCSM_DETACHED;
850 mutex_exit(&fcsm->sm_mutex);
851
852 fcsm = fcsm->sm_next;
853 }
854 }
855 mutex_exit(&fcsm_global_mutex);
856
857
858 /*
859 * Go ahead and detach the ports
860 */
861 mutex_enter(&fcsm_global_mutex);
862 while (fcsm_port_head != NULL) {
863 fcsm = fcsm_port_head;
864 mutex_exit(&fcsm_global_mutex);
865
866 /*
867 * Call fcsm_cleanup_port(). This cleansup and
868 * removes the fcsm structure from global linked list
869 */
870 fcsm_cleanup_port(fcsm);
871
872 /*
873 * Soft state cleanup done.
874 * Remember that fcsm struct doesn't exist anymore.
875 */
876
877 mutex_enter(&fcsm_global_mutex);
878 }
879
880 ddi_remove_minor_node(fcsm_dip, NULL);
881 fcsm_dip = NULL;
882 mutex_exit(&fcsm_global_mutex);
883 break;
884 }
885
886 case DDI_SUSPEND:
887 rval = DDI_SUCCESS;
888 break;
889
890 default:
891 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
892 "detach: unknown cmd 0x%x", cmd));
893 rval = DDI_FAILURE;
894 break;
895 }
896
897 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
898 "detach: end. cmd 0x%x, rval 0x%x", cmd, rval));
899
900 return (rval);
901 }
902
903
904 /* ARGSUSED */
905 static void
fcsm_force_port_detach_all(void)906 fcsm_force_port_detach_all(void)
907 {
908 fcsm_t *fcsm;
909
910 fcsm = fcsm_port_head;
911
912 while (fcsm) {
913 fcsm_cleanup_port(fcsm);
914 /*
915 * fcsm_cleanup_port will remove the current fcsm structure
916 * from the list, which will cause fcsm_port_head to point
917 * to what would have been the next structure on the list.
918 */
919 fcsm = fcsm_port_head;
920 }
921 }
922
923
924 /* ARGSUSED */
925 static int
fcsm_port_detach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_detach_cmd_t cmd)926 fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd)
927 {
928 int instance;
929 int rval = FC_FAILURE;
930 fcsm_t *fcsm;
931
932 instance = ddi_get_instance(pinfo->port_dip);
933
934 mutex_enter(&fcsm_global_mutex);
935 if (fcsm_detached) {
936 mutex_exit(&fcsm_global_mutex);
937
938 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
939 "port_detach: end. instance 0x%x, fcsm is detached",
940 instance));
941 return (FC_SUCCESS);
942 }
943 fcsm_num_detaching++; /* Set the flag */
944 mutex_exit(&fcsm_global_mutex);
945
946 /* Get the soft state structure */
947 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
948 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
949 "port_detach: instance 0x%x, cmd 0x%x get softstate failed",
950 instance, cmd));
951 mutex_enter(&fcsm_global_mutex);
952 fcsm_num_detaching--;
953 mutex_exit(&fcsm_global_mutex);
954 return (rval);
955 }
956
957 ASSERT(fcsm->sm_instance == instance);
958
959 /* If this instance is not attached, then fail the detach */
960 mutex_enter(&fcsm->sm_mutex);
961 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
962 mutex_exit(&fcsm->sm_mutex);
963 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
964 "port_detach: port is not attached");
965 mutex_enter(&fcsm_global_mutex);
966 fcsm_num_detaching--;
967 mutex_exit(&fcsm_global_mutex);
968 return (rval);
969 }
970 mutex_exit(&fcsm->sm_mutex);
971
972 /*
973 * If fcsm has been detached, then all instance has already been
974 * detached or are being detached. So succeed this detach.
975 */
976
977 switch (cmd) {
978 case FC_CMD_DETACH:
979 case FC_CMD_SUSPEND:
980 case FC_CMD_POWER_DOWN:
981 break;
982
983 default:
984 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
985 "port_detach: port unknown cmd 0x%x", cmd));
986 mutex_enter(&fcsm_global_mutex);
987 fcsm_num_detaching--;
988 mutex_exit(&fcsm_global_mutex);
989 return (rval);
990 };
991
992 if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) {
993 rval = FC_SUCCESS;
994 }
995
996 mutex_enter(&fcsm_global_mutex);
997 fcsm_num_detaching--;
998 mutex_exit(&fcsm_global_mutex);
999
1000 /* If it was a detach, then fcsm state structure no longer exists */
1001 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1002 "port_detach: end. cmd 0x%x rval 0x%x", cmd, rval));
1003 return (rval);
1004 }
1005
1006
1007 static int
fcsm_handle_port_detach(fc_ulp_port_info_t * pinfo,fcsm_t * fcsm,fc_detach_cmd_t cmd)1008 fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm,
1009 fc_detach_cmd_t cmd)
1010 {
1011 uint32_t flag;
1012 int count;
1013 #ifdef DEBUG
1014 char pathname[MAXPATHLEN];
1015 #endif /* DEBUG */
1016
1017 /*
1018 * If port is already powered down OR suspended and there is nothing
1019 * else to do then just return.
1020 * Otherwise, set the flag, so that no more new activity will be
1021 * initiated on this port.
1022 */
1023 mutex_enter(&fcsm->sm_mutex);
1024
1025 switch (cmd) {
1026 case FC_CMD_DETACH:
1027 flag = FCSM_DETACHING;
1028 break;
1029
1030 case FC_CMD_SUSPEND:
1031 case FC_CMD_POWER_DOWN:
1032 ((cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) :
1033 (flag = FCSM_POWER_DOWN));
1034 if (fcsm->sm_flags &
1035 (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
1036 fcsm->sm_flags |= flag;
1037 mutex_exit(&fcsm->sm_mutex);
1038 return (DDI_SUCCESS);
1039 }
1040 break;
1041
1042 default:
1043 mutex_exit(&fcsm->sm_mutex);
1044 return (DDI_FAILURE);
1045 };
1046
1047 fcsm->sm_flags |= flag;
1048
1049 /*
1050 * If some commands are pending OR callback in progress, then
1051 * wait for some finite amount of time for their completion.
1052 * TODO: add more checks here to check for cmd timeout, offline
1053 * timeout and other (??) threads.
1054 */
1055 count = 0;
1056 while ((count++ <= 30) && (fcsm->sm_ncmds || fcsm->sm_cb_count)) {
1057 mutex_exit(&fcsm->sm_mutex);
1058 delay(drv_usectohz(1000000));
1059 mutex_enter(&fcsm->sm_mutex);
1060 }
1061 if (fcsm->sm_ncmds || fcsm->sm_cb_count) {
1062 fcsm->sm_flags &= ~flag;
1063 mutex_exit(&fcsm->sm_mutex);
1064 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
1065 "port_detach: Failing suspend, port is busy");
1066 return (DDI_FAILURE);
1067 }
1068 if (flag == FCSM_DETACHING) {
1069 fcsm->sm_flags &= ~FCSM_DETACHING;
1070 fcsm->sm_flags |= FCSM_DETACHED;
1071 }
1072
1073 mutex_exit(&fcsm->sm_mutex);
1074
1075 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
1076 "port_detach: cmd 0x%x pathname <%s>",
1077 cmd, ddi_pathname(pinfo->port_dip, pathname)));
1078
1079 if (cmd == FC_CMD_DETACH) {
1080 fcsm_cleanup_port(fcsm);
1081 /*
1082 * Soft state cleanup done.
1083 * Always remember that fcsm struct doesn't exist anymore.
1084 */
1085 } else {
1086 fcsm_suspend_port(fcsm);
1087 }
1088
1089 return (DDI_SUCCESS);
1090 }
1091
1092 static void
fcsm_suspend_port(fcsm_t * fcsm)1093 fcsm_suspend_port(fcsm_t *fcsm)
1094 {
1095 mutex_enter(&fcsm->sm_mutex);
1096
1097 if (fcsm->sm_offline_tid != NULL) {
1098 timeout_id_t tid;
1099
1100 tid = fcsm->sm_offline_tid;
1101 fcsm->sm_offline_tid = (timeout_id_t)NULL;
1102 mutex_exit(&fcsm->sm_mutex);
1103 (void) untimeout(tid);
1104 mutex_enter(&fcsm->sm_mutex);
1105 fcsm->sm_flags |= FCSM_RESTORE_OFFLINE_TIMEOUT;
1106 }
1107
1108 if (fcsm->sm_retry_tid != NULL) {
1109 timeout_id_t tid;
1110
1111 tid = fcsm->sm_retry_tid;
1112 fcsm->sm_retry_tid = (timeout_id_t)NULL;
1113 mutex_exit(&fcsm->sm_mutex);
1114 (void) untimeout(tid);
1115 mutex_enter(&fcsm->sm_mutex);
1116 fcsm->sm_flags |= FCSM_RESTORE_RETRY_TIMEOUT;
1117 }
1118
1119 mutex_exit(&fcsm->sm_mutex);
1120 }
1121
1122 static void
fcsm_resume_port(fcsm_t * fcsm)1123 fcsm_resume_port(fcsm_t *fcsm)
1124 {
1125 mutex_enter(&fcsm->sm_mutex);
1126
1127 if (fcsm->sm_flags & FCSM_RESTORE_OFFLINE_TIMEOUT) {
1128 fcsm->sm_flags &= ~FCSM_RESTORE_OFFLINE_TIMEOUT;
1129
1130 /*
1131 * If port if offline, link is not marked down and offline
1132 * timer is not already running, then restart offline timer.
1133 */
1134 if (!(fcsm->sm_flags & FCSM_LINK_DOWN) &&
1135 fcsm->sm_offline_tid == NULL &&
1136 (fcsm->sm_flags & FCSM_PORT_OFFLINE)) {
1137 fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1138 (caddr_t)fcsm, fcsm_offline_ticks);
1139 }
1140 }
1141
1142 if (fcsm->sm_flags & FCSM_RESTORE_RETRY_TIMEOUT) {
1143 fcsm->sm_flags &= ~FCSM_RESTORE_RETRY_TIMEOUT;
1144
1145 /*
1146 * If retry queue is not suspended and some cmds are waiting
1147 * to be retried, then restart the retry timer
1148 */
1149 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1150 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1151 (caddr_t)fcsm, fcsm_retry_ticks);
1152 }
1153 }
1154 mutex_exit(&fcsm->sm_mutex);
1155 }
1156
1157 static void
fcsm_cleanup_port(fcsm_t * fcsm)1158 fcsm_cleanup_port(fcsm_t *fcsm)
1159 {
1160 fcsm_t *curr, *prev;
1161 int status;
1162 fcsm_job_t *job;
1163
1164 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1165 "fcsm_cleanup_port: entered"));
1166
1167 /*
1168 * Kill the job thread
1169 */
1170 job = fcsm_alloc_job(KM_SLEEP);
1171 ASSERT(job != NULL);
1172 fcsm_init_job(job, fcsm->sm_instance, FCSM_JOB_THREAD_SHUTDOWN,
1173 FCSM_JOBFLAG_SYNC, NULL, NULL, NULL, NULL);
1174
1175 status = fcsm_process_job(job, 0);
1176 ASSERT(status == FC_SUCCESS);
1177
1178 ASSERT(job->job_result == FC_SUCCESS);
1179 fcsm_dealloc_job(job);
1180
1181 /*
1182 * We got here after ensuring the no commands are pending or active.
1183 * Therefore retry timeout thread should NOT be running.
1184 * Kill the offline timeout thread if currently running.
1185 */
1186 mutex_enter(&fcsm->sm_mutex);
1187
1188 ASSERT(fcsm->sm_retry_tid == NULL);
1189
1190 if (fcsm->sm_offline_tid != NULL) {
1191 timeout_id_t tid;
1192
1193 tid = fcsm->sm_offline_tid;
1194 fcsm->sm_offline_tid = (timeout_id_t)NULL;
1195 mutex_exit(&fcsm->sm_mutex);
1196 (void) untimeout(tid);
1197 } else {
1198 mutex_exit(&fcsm->sm_mutex);
1199 }
1200
1201 /* Remove from the fcsm state structure from global linked list */
1202 mutex_enter(&fcsm_global_mutex);
1203 curr = fcsm_port_head;
1204 prev = NULL;
1205 while (curr != fcsm && curr != NULL) {
1206 prev = curr;
1207 curr = curr->sm_next;
1208 }
1209 ASSERT(curr != NULL);
1210
1211 if (prev == NULL) {
1212 fcsm_port_head = curr->sm_next;
1213 } else {
1214 prev->sm_next = curr->sm_next;
1215 }
1216 mutex_exit(&fcsm_global_mutex);
1217
1218 if (fcsm->sm_cmd_cache != NULL) {
1219 kmem_cache_destroy(fcsm->sm_cmd_cache);
1220 }
1221 cv_destroy(&fcsm->sm_job_cv);
1222 mutex_destroy(&fcsm->sm_mutex);
1223
1224 /* Free the fcsm state structure */
1225 ddi_soft_state_free(fcsm_state, fcsm->sm_instance);
1226 }
1227
1228
1229 /* ARGSUSED */
1230 static void
fcsm_statec_cb(opaque_t ulph,opaque_t port_handle,uint32_t port_state,uint32_t port_top,fc_portmap_t * devlist,uint32_t dev_cnt,uint32_t port_sid)1231 fcsm_statec_cb(opaque_t ulph, opaque_t port_handle, uint32_t port_state,
1232 uint32_t port_top, fc_portmap_t *devlist, uint32_t dev_cnt,
1233 uint32_t port_sid)
1234 {
1235 fcsm_t *fcsm;
1236 timeout_id_t offline_tid, retry_tid;
1237
1238 mutex_enter(&fcsm_global_mutex);
1239 if (fcsm_detached) {
1240 mutex_exit(&fcsm_global_mutex);
1241 return;
1242 }
1243
1244 fcsm = ddi_get_soft_state(fcsm_state,
1245 fc_ulp_get_port_instance(port_handle));
1246 if (fcsm == NULL) {
1247 mutex_exit(&fcsm_global_mutex);
1248 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1249 "statec_cb: instance 0x%x not found",
1250 fc_ulp_get_port_instance(port_handle)));
1251 return;
1252 }
1253 mutex_enter(&fcsm->sm_mutex);
1254 ASSERT(fcsm->sm_instance == fc_ulp_get_port_instance(port_handle));
1255 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
1256 mutex_exit(&fcsm->sm_mutex);
1257 mutex_exit(&fcsm_global_mutex);
1258 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, fcsm, NULL,
1259 "statec_cb: port not attached"));
1260 return;
1261 }
1262
1263 ASSERT(fcsm->sm_cb_count >= 0);
1264
1265 fcsm->sm_cb_count++;
1266 mutex_exit(&fcsm->sm_mutex);
1267 mutex_exit(&fcsm_global_mutex);
1268
1269 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1270 "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d",
1271 fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state)), port_state,
1272 fcsm_topology_to_str(port_top), port_top, dev_cnt));
1273
1274 fcsm_disp_devlist(fcsm, devlist, dev_cnt);
1275
1276 mutex_enter(&fcsm->sm_mutex);
1277
1278 /*
1279 * Reset the Mgmt server Login flag, so that login is performed again.
1280 */
1281 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
1282
1283 fcsm->sm_sid = port_sid;
1284 fcsm->sm_port_top = port_top;
1285 fcsm->sm_port_state = port_state;
1286
1287 switch (port_state) {
1288 case FC_STATE_OFFLINE:
1289 case FC_STATE_RESET:
1290 case FC_STATE_RESET_REQUESTED:
1291 fcsm->sm_flags |= FCSM_PORT_OFFLINE;
1292 break;
1293
1294 case FC_STATE_ONLINE:
1295 case FC_STATE_LOOP:
1296 case FC_STATE_LIP:
1297 case FC_STATE_LIP_LBIT_SET:
1298 fcsm->sm_flags &= ~FCSM_PORT_OFFLINE;
1299 fcsm->sm_flags &= ~FCSM_LINK_DOWN;
1300 break;
1301
1302 case FC_STATE_NAMESERVICE:
1303 case FC_STATE_DEVICE_CHANGE:
1304 case FC_STATE_TARGET_PORT_RESET:
1305 default:
1306 /* Do nothing */
1307 break;
1308 }
1309
1310 offline_tid = retry_tid = NULL;
1311 if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1312 /*
1313 * Port is offline.
1314 * Suspend cmd processing and start offline timeout thread.
1315 */
1316 if (fcsm->sm_offline_tid == NULL) {
1317 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1318 "statec_cb: schedule offline timeout thread"));
1319 fcsm->sm_flags |= FCSM_CMD_RETRY_Q_SUSPENDED;
1320 /* Stop the cmd retry thread */
1321 retry_tid = fcsm->sm_retry_tid;
1322 fcsm->sm_retry_tid = (timeout_id_t)NULL;
1323
1324 fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1325 (caddr_t)fcsm, fcsm_offline_ticks);
1326 }
1327
1328 } else {
1329 /*
1330 * Port is online.
1331 * Cancel offline timeout thread and resume command processing.
1332 */
1333 if (fcsm->sm_offline_tid) {
1334 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1335 "statec_cb: cancel offline timeout thread"));
1336 offline_tid = fcsm->sm_offline_tid;
1337 fcsm->sm_offline_tid = (timeout_id_t)NULL;
1338 }
1339
1340 fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1341 /* Start retry thread if needed */
1342 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1343 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1344 (caddr_t)fcsm, fcsm_retry_ticks);
1345 }
1346 }
1347
1348 mutex_exit(&fcsm->sm_mutex);
1349
1350 if (offline_tid != NULL) {
1351 (void) untimeout(offline_tid);
1352 }
1353
1354 if (retry_tid != NULL) {
1355 (void) untimeout(retry_tid);
1356 }
1357
1358 mutex_enter(&fcsm->sm_mutex);
1359 fcsm->sm_cb_count--;
1360 ASSERT(fcsm->sm_cb_count >= 0);
1361 mutex_exit(&fcsm->sm_mutex);
1362 }
1363
1364
1365 static void
fcsm_offline_timeout(void * handle)1366 fcsm_offline_timeout(void *handle)
1367 {
1368 fcsm_t *fcsm = (fcsm_t *)handle;
1369
1370 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1371 "offline_timeout"));
1372
1373 mutex_enter(&fcsm->sm_mutex);
1374 if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1375 fcsm->sm_flags |= FCSM_LINK_DOWN;
1376 }
1377 fcsm->sm_offline_tid = (timeout_id_t)NULL;
1378 fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1379
1380 /* Start the retry thread if needed */
1381 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1382 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1383 "offline_timeout: reschedule cmd retry thread"));
1384 ASSERT(fcsm->sm_retry_tid == NULL);
1385 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1386 (caddr_t)fcsm, fcsm_retry_ticks);
1387 }
1388 mutex_exit(&fcsm->sm_mutex);
1389 }
1390
1391 /* ARGSUSED */
1392 static int
fcsm_els_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)1393 fcsm_els_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1394 uint32_t claimed)
1395 {
1396 return (FC_UNCLAIMED);
1397 }
1398
1399
1400 /* ARGSUSED */
1401 static int
fcsm_data_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)1402 fcsm_data_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1403 uint32_t claimed)
1404 {
1405 return (FC_UNCLAIMED);
1406 }
1407
1408
1409 /* ARGSUSED */
1410 static int
fcsm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rval_p)1411 fcsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1412 int *rval_p)
1413 {
1414 int retval = 0;
1415
1416 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: start"));
1417
1418 mutex_enter(&fcsm_global_mutex);
1419 if (!(fcsm_flag & FCSM_OPEN)) {
1420 mutex_exit(&fcsm_global_mutex);
1421 return (ENXIO);
1422 }
1423 mutex_exit(&fcsm_global_mutex);
1424
1425 /* Allow only root to talk */
1426 if (drv_priv(credp)) {
1427 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1428 "ioctl: end (disallowing underprivileged user)"));
1429 return (EPERM);
1430 }
1431
1432 switch (cmd) {
1433
1434 case FCSMIO_CMD: {
1435 fcio_t fcio;
1436 int status;
1437 #ifdef _MULTI_DATAMODEL
1438 switch (ddi_model_convert_from(mode & FMODELS)) {
1439 case DDI_MODEL_ILP32: {
1440 struct fcio32 fcio32;
1441
1442 if (status = ddi_copyin((void *)arg, (void *)&fcio32,
1443 sizeof (struct fcio32), mode)) {
1444 retval = EFAULT;
1445 break;
1446 }
1447 fcio.fcio_xfer = fcio32.fcio_xfer;
1448 fcio.fcio_cmd = fcio32.fcio_cmd;
1449 fcio.fcio_flags = fcio32.fcio_flags;
1450 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
1451 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
1452 fcio.fcio_ibuf = (caddr_t)(long)fcio32.fcio_ibuf;
1453 fcio.fcio_olen = (size_t)fcio32.fcio_olen;
1454 fcio.fcio_obuf = (caddr_t)(long)fcio32.fcio_obuf;
1455 fcio.fcio_alen = (size_t)fcio32.fcio_alen;
1456 fcio.fcio_abuf = (caddr_t)(long)fcio32.fcio_abuf;
1457 fcio.fcio_errno = fcio32.fcio_errno;
1458 break;
1459 }
1460
1461 case DDI_MODEL_NONE:
1462 if (status = ddi_copyin((void *)arg, (void *)&fcio,
1463 sizeof (fcio_t), mode)) {
1464 retval = EFAULT;
1465 }
1466 break;
1467 }
1468 #else /* _MULTI_DATAMODEL */
1469 if (status = ddi_copyin((void *)arg, (void *)&fcio,
1470 sizeof (fcio_t), mode)) {
1471 retval = EFAULT;
1472 break;
1473 }
1474 #endif /* _MULTI_DATAMODEL */
1475 if (!status) {
1476 retval = fcsm_fciocmd(arg, mode, credp, &fcio);
1477 }
1478 break;
1479 }
1480
1481 default:
1482 retval = ENOTTY;
1483 break;
1484 }
1485
1486 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: end"));
1487 return (retval);
1488 }
1489
1490 /* ARGSUSED */
1491 static int
fcsm_port_ioctl(opaque_t ulph,opaque_t port_handle,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rval,uint32_t claimed)1492 fcsm_port_ioctl(opaque_t ulph, opaque_t port_handle, dev_t dev, int cmd,
1493 intptr_t arg, int mode, cred_t *credp, int *rval, uint32_t claimed)
1494 {
1495 return (FC_UNCLAIMED);
1496 }
1497
1498
1499 /* ARGSUSED */
1500 static int
fcsm_fciocmd(intptr_t arg,int mode,cred_t * credp,fcio_t * fcio)1501 fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
1502 {
1503 int retval = 0;
1504
1505 switch (fcio->fcio_cmd) {
1506 case FCSMIO_CT_CMD: {
1507 fcsm_t *fcsm;
1508 caddr_t user_ibuf, user_obuf;
1509 caddr_t req_iu, rsp_iu, abuf;
1510 int status, instance, count;
1511
1512 if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1513 (fcio->fcio_ilen == 0) || (fcio->fcio_ibuf == 0) ||
1514 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0) ||
1515 (fcio->fcio_alen == 0) || (fcio->fcio_abuf == 0) ||
1516 (fcio->fcio_flags != 0) || (fcio->fcio_cmd_flags != 0) ||
1517 (fcio->fcio_ilen > FCSM_MAX_CT_SIZE) ||
1518 (fcio->fcio_olen > FCSM_MAX_CT_SIZE) ||
1519 (fcio->fcio_alen > MAXPATHLEN)) {
1520 retval = EINVAL;
1521 break;
1522 }
1523
1524 /*
1525 * Get the destination port for which this ioctl
1526 * is targeted. The abuf will have the fp_minor
1527 * number.
1528 */
1529 abuf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
1530 ASSERT(abuf != NULL);
1531 if (ddi_copyin(fcio->fcio_abuf, abuf, fcio->fcio_alen, mode)) {
1532 retval = EFAULT;
1533 kmem_free(abuf, fcio->fcio_alen);
1534 break;
1535 }
1536
1537 instance = *((int *)abuf);
1538 kmem_free(abuf, fcio->fcio_alen);
1539
1540 if (instance < 0) {
1541 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1542 "fciocmd: instance 0x%x, invalid instance",
1543 instance));
1544 retval = ENXIO;
1545 break;
1546 }
1547
1548 /*
1549 * We confirmed that path corresponds to our port driver
1550 * and a valid instance.
1551 * If this port instance is not yet attached, then wait
1552 * for a finite time for attach to complete
1553 */
1554 fcsm = ddi_get_soft_state(fcsm_state, instance);
1555 count = 0;
1556 while (count++ <= 30) {
1557 if (fcsm != NULL) {
1558 mutex_enter(&fcsm->sm_mutex);
1559 if (fcsm->sm_flags & FCSM_ATTACHED) {
1560 mutex_exit(&fcsm->sm_mutex);
1561 break;
1562 }
1563 mutex_exit(&fcsm->sm_mutex);
1564 }
1565 if (count == 1) {
1566 FCSM_DEBUG(SMDL_TRACE,
1567 (CE_WARN, SM_LOG, NULL, NULL,
1568 "fciocmd: instance 0x%x, "
1569 "wait for port attach", instance));
1570 }
1571 delay(drv_usectohz(1000000));
1572 fcsm = ddi_get_soft_state(fcsm_state, instance);
1573 }
1574 if (count > 30) {
1575 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1576 "fciocmd: instance 0x%x, port not attached",
1577 instance));
1578 retval = ENXIO;
1579 break;
1580 }
1581
1582 req_iu = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
1583 rsp_iu = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1584 ASSERT((req_iu != NULL) && (rsp_iu != NULL));
1585
1586 if (ddi_copyin(fcio->fcio_ibuf, req_iu,
1587 fcio->fcio_ilen, mode)) {
1588 retval = EFAULT;
1589 kmem_free(req_iu, fcio->fcio_ilen);
1590 kmem_free(rsp_iu, fcio->fcio_olen);
1591 break;
1592 }
1593
1594 user_ibuf = fcio->fcio_ibuf;
1595 user_obuf = fcio->fcio_obuf;
1596 fcio->fcio_ibuf = req_iu;
1597 fcio->fcio_obuf = rsp_iu;
1598
1599 status = fcsm_ct_passthru(fcsm->sm_instance, fcio, KM_SLEEP,
1600 FCSM_JOBFLAG_SYNC, NULL);
1601 if (status != FC_SUCCESS) {
1602 retval = EIO;
1603 }
1604
1605 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1606 "fciocmd: cmd 0x%x completion status 0x%x",
1607 fcio->fcio_cmd, status));
1608 fcio->fcio_errno = status;
1609 fcio->fcio_ibuf = user_ibuf;
1610 fcio->fcio_obuf = user_obuf;
1611
1612 if (ddi_copyout(rsp_iu, fcio->fcio_obuf,
1613 fcio->fcio_olen, mode)) {
1614 retval = EFAULT;
1615 kmem_free(req_iu, fcio->fcio_ilen);
1616 kmem_free(rsp_iu, fcio->fcio_olen);
1617 break;
1618 }
1619
1620 kmem_free(req_iu, fcio->fcio_ilen);
1621 kmem_free(rsp_iu, fcio->fcio_olen);
1622
1623 if (fcsm_fcio_copyout(fcio, arg, mode)) {
1624 retval = EFAULT;
1625 }
1626 break;
1627 }
1628
1629 case FCSMIO_ADAPTER_LIST: {
1630 fc_hba_list_t *list;
1631 int count;
1632
1633 if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1634 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
1635 retval = EINVAL;
1636 break;
1637 }
1638
1639 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1640
1641 if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
1642 retval = EFAULT;
1643 break;
1644 }
1645 list->version = FC_HBA_LIST_VERSION;
1646
1647 if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
1648 retval = EFAULT;
1649 break;
1650 }
1651
1652 count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
1653 list->numAdapters);
1654 if (count < 0) {
1655 /* Did something go wrong? */
1656 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1657 "Error fetching adapter list."));
1658 retval = ENXIO;
1659 kmem_free(list, fcio->fcio_olen);
1660 break;
1661 }
1662 /* Sucess (or short buffer) */
1663 list->numAdapters = count;
1664 if (ddi_copyout(list, fcio->fcio_obuf,
1665 fcio->fcio_olen, mode)) {
1666 retval = EFAULT;
1667 }
1668 kmem_free(list, fcio->fcio_olen);
1669 break;
1670 }
1671
1672 default:
1673 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1674 "fciocmd: unknown cmd <0x%x>", fcio->fcio_cmd));
1675 retval = ENOTTY;
1676 break;
1677 }
1678
1679 return (retval);
1680 }
1681
1682 static int
fcsm_fcio_copyout(fcio_t * fcio,intptr_t arg,int mode)1683 fcsm_fcio_copyout(fcio_t *fcio, intptr_t arg, int mode)
1684 {
1685 int status;
1686
1687 #ifdef _MULTI_DATAMODEL
1688 switch (ddi_model_convert_from(mode & FMODELS)) {
1689 case DDI_MODEL_ILP32: {
1690 struct fcio32 fcio32;
1691
1692 fcio32.fcio_xfer = fcio->fcio_xfer;
1693 fcio32.fcio_cmd = fcio->fcio_cmd;
1694 fcio32.fcio_flags = fcio->fcio_flags;
1695 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
1696 fcio32.fcio_ilen = fcio->fcio_ilen;
1697 fcio32.fcio_ibuf = (caddr32_t)(long)fcio->fcio_ibuf;
1698 fcio32.fcio_olen = fcio->fcio_olen;
1699 fcio32.fcio_obuf = (caddr32_t)(long)fcio->fcio_obuf;
1700 fcio32.fcio_alen = fcio->fcio_alen;
1701 fcio32.fcio_abuf = (caddr32_t)(long)fcio->fcio_abuf;
1702 fcio32.fcio_errno = fcio->fcio_errno;
1703
1704 status = ddi_copyout((void *)&fcio32, (void *)arg,
1705 sizeof (struct fcio32), mode);
1706 break;
1707 }
1708 case DDI_MODEL_NONE:
1709 status = ddi_copyout((void *)fcio, (void *)arg,
1710 sizeof (fcio_t), mode);
1711 break;
1712 }
1713 #else /* _MULTI_DATAMODEL */
1714 status = ddi_copyout((void *)fcio, (void *)arg, sizeof (fcio_t), mode);
1715 #endif /* _MULTI_DATAMODEL */
1716
1717 return (status);
1718 }
1719
1720
1721 /* ARGSUSED */
1722 static int
fcsm_open(dev_t * devp,int flags,int otyp,cred_t * credp)1723 fcsm_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1724 {
1725 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "open"));
1726
1727 if (otyp != OTYP_CHR) {
1728 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1729 "fcsm_open: failed. open type 0x%x for minor 0x%x is not "
1730 "OTYP_CHR", otyp, getminor(*devp)));
1731 return (EINVAL);
1732 }
1733
1734 /*
1735 * Allow anybody to open (both root and non-root users).
1736 * Previlege level checks are made on the per ioctl basis.
1737 */
1738 mutex_enter(&fcsm_global_mutex);
1739 if (flags & FEXCL) {
1740 if (fcsm_flag & FCSM_OPEN) {
1741 mutex_exit(&fcsm_global_mutex);
1742 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1743 "fcsm_open: exclusive open of 0x%x failed",
1744 getminor(*devp)));
1745 return (EBUSY);
1746 } else {
1747 ASSERT(fcsm_flag == FCSM_IDLE);
1748 fcsm_flag |= FCSM_EXCL;
1749 }
1750 } else {
1751 if (fcsm_flag & FCSM_EXCL) {
1752 mutex_exit(&fcsm_global_mutex);
1753 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1754 "fcsm_open: failed. Device minor 0x%x is in "
1755 "exclusive open mode", getminor(*devp)));
1756 return (EBUSY);
1757 }
1758
1759 }
1760 fcsm_flag |= FCSM_OPEN;
1761 mutex_exit(&fcsm_global_mutex);
1762 return (0);
1763 }
1764
1765
1766 /* ARGSUSED */
1767 static int
fcsm_close(dev_t dev,int flag,int otyp,cred_t * credp)1768 fcsm_close(dev_t dev, int flag, int otyp, cred_t *credp)
1769 {
1770 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "close"));
1771
1772 if (otyp != OTYP_CHR) {
1773 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1774 "fcsm_close: failed. close type 0x%x for minor 0x%x is not "
1775 "OTYP_CHR", otyp, getminor(dev)));
1776 return (EINVAL);
1777 }
1778
1779 mutex_enter(&fcsm_global_mutex);
1780 if ((fcsm_flag & FCSM_OPEN) == 0) {
1781 mutex_exit(&fcsm_global_mutex);
1782 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1783 "fcsm_close: failed. minor 0x%x is already closed",
1784 getminor(dev)));
1785 return (ENODEV);
1786 }
1787 fcsm_flag = FCSM_IDLE;
1788 mutex_exit(&fcsm_global_mutex);
1789 return (0);
1790 }
1791
1792
1793 /* ARGSUSED */
1794 static void
fcsm_disp_devlist(fcsm_t * fcsm,fc_portmap_t * devlist,uint32_t dev_cnt)1795 fcsm_disp_devlist(fcsm_t *fcsm, fc_portmap_t *devlist, uint32_t dev_cnt)
1796 {
1797 fc_portmap_t *map;
1798 uint32_t i;
1799
1800 if (dev_cnt == 0) {
1801 return;
1802 }
1803
1804 ASSERT(devlist != NULL);
1805 for (i = 0; i < dev_cnt; i++) {
1806 map = &devlist[i];
1807 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1808 "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x "
1809 "state (0x%x) "
1810 "type <%s>(0x%x) "
1811 "flags (0x%x)",
1812 i, map->map_did.port_id,
1813 map->map_pwwn.raw_wwn[0], map->map_pwwn.raw_wwn[1],
1814 map->map_pwwn.raw_wwn[2], map->map_pwwn.raw_wwn[3],
1815 map->map_pwwn.raw_wwn[4], map->map_pwwn.raw_wwn[5],
1816 map->map_pwwn.raw_wwn[6], map->map_pwwn.raw_wwn[7],
1817 map->map_state,
1818 fcsm_dev_type_to_str(map->map_type), map->map_type,
1819 map->map_flags));
1820 }
1821 }
1822
1823 /* ARGSUSED */
1824 static void
fcsm_display(int level,int flags,fcsm_t * fcsm,fc_packet_t * pkt,const char * fmt,...)1825 fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt,
1826 const char *fmt, ...)
1827 {
1828 caddr_t buf;
1829 va_list ap;
1830
1831 buf = kmem_zalloc(256, KM_NOSLEEP);
1832 if (buf == NULL) {
1833 return;
1834 }
1835
1836 if (fcsm) {
1837 (void) sprintf(buf + strlen(buf), "fcsm(%d): ",
1838 ddi_get_instance(fcsm->sm_port_info.port_dip));
1839 } else {
1840 (void) sprintf(buf, "fcsm: ");
1841 }
1842
1843 va_start(ap, fmt);
1844 (void) vsprintf(buf + strlen(buf), fmt, ap);
1845 va_end(ap);
1846
1847 if (pkt) {
1848 caddr_t state, reason, action, expln;
1849
1850 (void) fc_ulp_pkt_error(pkt, &state, &reason, &action, &expln);
1851
1852 (void) sprintf(buf + strlen(buf),
1853 " state: %s(0x%x); reason: %s(0x%x)",
1854 state, pkt->pkt_state, reason, pkt->pkt_reason);
1855 }
1856
1857 switch (flags) {
1858 case SM_LOG:
1859 cmn_err(level, "!%s", buf);
1860 break;
1861
1862 case SM_CONSOLE:
1863 cmn_err(level, "^%s", buf);
1864 break;
1865
1866 default:
1867 cmn_err(level, "%s", buf);
1868 break;
1869 }
1870
1871 kmem_free(buf, 256);
1872 }
1873
1874
1875 /*
1876 * Convert FC packet state to FC errno
1877 */
1878 int
fcsm_pkt_state_to_rval(uchar_t state,uint32_t reason)1879 fcsm_pkt_state_to_rval(uchar_t state, uint32_t reason)
1880 {
1881 int count;
1882
1883 if (state == FC_PKT_LOCAL_RJT && (reason == FC_REASON_NO_CONNECTION ||
1884 reason == FC_REASON_LOGIN_REQUIRED)) {
1885 return (FC_LOGINREQ);
1886 } else if (state == FC_PKT_PORT_OFFLINE &&
1887 reason == FC_REASON_LOGIN_REQUIRED) {
1888 return (FC_LOGINREQ);
1889 }
1890
1891 for (count = 0; count < sizeof (fcsm_xlat_pkt_state) /
1892 sizeof (fcsm_xlat_pkt_state[0]); count++) {
1893 if (fcsm_xlat_pkt_state[count].xlat_state == state) {
1894 return (fcsm_xlat_pkt_state[count].xlat_rval);
1895 }
1896 }
1897
1898 return (FC_FAILURE);
1899 }
1900
1901
1902 /*
1903 * Convert port state state to descriptive string
1904 */
1905 caddr_t
fcsm_port_state_to_str(uint32_t port_state)1906 fcsm_port_state_to_str(uint32_t port_state)
1907 {
1908 int count;
1909
1910 for (count = 0; count < sizeof (fcsm_xlat_port_state) /
1911 sizeof (fcsm_xlat_port_state[0]); count++) {
1912 if (fcsm_xlat_port_state[count].xlat_pstate == port_state) {
1913 return (fcsm_xlat_port_state[count].xlat_state_str);
1914 }
1915 }
1916
1917 return (NULL);
1918 }
1919
1920
1921 /*
1922 * Convert port topology state to descriptive string
1923 */
1924 caddr_t
fcsm_topology_to_str(uint32_t topology)1925 fcsm_topology_to_str(uint32_t topology)
1926 {
1927 int count;
1928
1929 for (count = 0; count < sizeof (fcsm_xlat_topology) /
1930 sizeof (fcsm_xlat_topology[0]); count++) {
1931 if (fcsm_xlat_topology[count].xlat_top == topology) {
1932 return (fcsm_xlat_topology[count].xlat_top_str);
1933 }
1934 }
1935
1936 return (NULL);
1937 }
1938
1939
1940 /*
1941 * Convert port topology state to descriptive string
1942 */
1943 static caddr_t
fcsm_dev_type_to_str(uint32_t type)1944 fcsm_dev_type_to_str(uint32_t type)
1945 {
1946 int count;
1947
1948 for (count = 0; count < sizeof (fcsm_xlat_dev_type) /
1949 sizeof (fcsm_xlat_dev_type[0]); count++) {
1950 if (fcsm_xlat_dev_type[count].xlat_type == type) {
1951 return (fcsm_xlat_dev_type[count].xlat_str);
1952 }
1953 }
1954
1955 return (NULL);
1956 }
1957
1958 static int
fcsm_cmd_cache_constructor(void * buf,void * cdarg,int kmflags)1959 fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags)
1960 {
1961 fcsm_cmd_t *cmd = (fcsm_cmd_t *)buf;
1962 fcsm_t *fcsm = (fcsm_t *)cdarg;
1963 int (*callback)(caddr_t);
1964 fc_packet_t *pkt;
1965 fc_ulp_port_info_t *pinfo;
1966
1967 ASSERT(fcsm != NULL && buf != NULL);
1968 callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
1969
1970 cmd->cmd_fp_pkt = &cmd->cmd_fc_packet;
1971 cmd->cmd_job = NULL;
1972 cmd->cmd_fcsm = fcsm;
1973 cmd->cmd_dma_flags = 0;
1974
1975 pkt = &cmd->cmd_fc_packet;
1976
1977 pkt->pkt_ulp_rscn_infop = NULL;
1978 pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t));
1979 pkt->pkt_ulp_private = (opaque_t)cmd;
1980
1981 if (!(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
1982 pinfo = &fcsm->sm_port_info;
1983 if (ddi_dma_alloc_handle(pinfo->port_dip,
1984 pinfo->port_cmd_dma_attr,
1985 callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1986 return (1);
1987 }
1988
1989 if (ddi_dma_alloc_handle(pinfo->port_dip,
1990 pinfo->port_resp_dma_attr,
1991 callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1992 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1993 return (1);
1994 }
1995 } else {
1996 pkt->pkt_cmd_dma = NULL;
1997 pkt->pkt_cmd = NULL;
1998 pkt->pkt_resp_dma = NULL;
1999 pkt->pkt_resp = NULL;
2000 }
2001
2002 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
2003 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
2004 pkt->pkt_data_cookie_cnt = 0;
2005 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
2006 pkt->pkt_data_cookie = NULL;
2007
2008 return (0);
2009 }
2010
2011
2012 /* ARGSUSED */
2013 static void
fcsm_cmd_cache_destructor(void * buf,void * cdarg)2014 fcsm_cmd_cache_destructor(void *buf, void *cdarg)
2015 {
2016 fcsm_cmd_t *cmd = (fcsm_cmd_t *)buf;
2017 fcsm_t *fcsm = (fcsm_t *)cdarg;
2018 fc_packet_t *pkt;
2019
2020 ASSERT(fcsm == cmd->cmd_fcsm);
2021
2022 pkt = cmd->cmd_fp_pkt;
2023
2024 if (pkt->pkt_cmd_dma != NULL) {
2025 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
2026 }
2027
2028 if (pkt->pkt_resp_dma != NULL) {
2029 ddi_dma_free_handle(&pkt->pkt_resp_dma);
2030 }
2031 }
2032
2033
2034 static fcsm_cmd_t *
fcsm_alloc_cmd(fcsm_t * fcsm,uint32_t cmd_len,uint32_t resp_len,int sleep)2035 fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
2036 {
2037 fcsm_cmd_t *cmd;
2038 fc_packet_t *pkt;
2039 int rval;
2040 ulong_t real_len;
2041 int (*callback)(caddr_t);
2042 ddi_dma_cookie_t pkt_cookie;
2043 ddi_dma_cookie_t *cp;
2044 uint32_t cnt;
2045 fc_ulp_port_info_t *pinfo;
2046
2047 ASSERT(fcsm != NULL);
2048 pinfo = &fcsm->sm_port_info;
2049
2050 callback = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
2051
2052 cmd = (fcsm_cmd_t *)kmem_cache_alloc(fcsm->sm_cmd_cache, sleep);
2053 if (cmd == NULL) {
2054 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, fcsm, NULL,
2055 "alloc_cmd: kmem_cache_alloc failed"));
2056 return (NULL);
2057 }
2058
2059 cmd->cmd_retry_count = 0;
2060 cmd->cmd_max_retries = 0;
2061 cmd->cmd_retry_interval = 0;
2062 cmd->cmd_transport = NULL;
2063
2064 ASSERT(cmd->cmd_dma_flags == 0);
2065 ASSERT(cmd->cmd_fp_pkt == &cmd->cmd_fc_packet);
2066 pkt = cmd->cmd_fp_pkt;
2067
2068 /* Zero out the important fc_packet fields */
2069 pkt->pkt_pd = NULL;
2070 pkt->pkt_datalen = 0;
2071 pkt->pkt_data = NULL;
2072 pkt->pkt_state = 0;
2073 pkt->pkt_action = 0;
2074 pkt->pkt_reason = 0;
2075 pkt->pkt_expln = 0;
2076
2077 /*
2078 * Now that pkt_pd is initialized, we can call fc_ulp_init_packet
2079 */
2080
2081 if (fc_ulp_init_packet((opaque_t)pinfo->port_handle, pkt, sleep)
2082 != FC_SUCCESS) {
2083 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2084 return (NULL);
2085 }
2086
2087 if ((cmd_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2088 ASSERT(pkt->pkt_cmd_dma != NULL);
2089
2090 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2091 fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2092 callback, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2093 &pkt->pkt_cmd_acc);
2094
2095 if (rval != DDI_SUCCESS) {
2096 (void) fc_ulp_uninit_packet(
2097 (opaque_t)pinfo->port_handle, pkt);
2098 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2099 fcsm_free_cmd_dma(cmd);
2100 return (NULL);
2101 }
2102
2103 cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_MEM;
2104
2105 if (real_len < cmd_len) {
2106 (void) fc_ulp_uninit_packet(
2107 (opaque_t)pinfo->port_handle, pkt);
2108 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2109 fcsm_free_cmd_dma(cmd);
2110 return (NULL);
2111 }
2112
2113 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2114 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2115 callback, NULL, &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2116
2117 if (rval != DDI_DMA_MAPPED) {
2118 (void) fc_ulp_uninit_packet(
2119 (opaque_t)pinfo->port_handle, pkt);
2120 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2121 fcsm_free_cmd_dma(cmd);
2122 return (NULL);
2123 }
2124
2125 cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_BIND;
2126
2127 if (pkt->pkt_cmd_cookie_cnt >
2128 pinfo->port_cmd_dma_attr->dma_attr_sgllen) {
2129 (void) fc_ulp_uninit_packet(
2130 (opaque_t)pinfo->port_handle, pkt);
2131 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2132 fcsm_free_cmd_dma(cmd);
2133 return (NULL);
2134 }
2135
2136 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2137
2138 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2139 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2140 KM_NOSLEEP);
2141
2142 if (cp == NULL) {
2143 (void) fc_ulp_uninit_packet(
2144 (opaque_t)pinfo->port_handle, pkt);
2145 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2146 fcsm_free_cmd_dma(cmd);
2147 return (NULL);
2148 }
2149
2150 *cp = pkt_cookie;
2151 cp++;
2152 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2153 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2154 *cp = pkt_cookie;
2155 }
2156 } else if (cmd_len != 0) {
2157 pkt->pkt_cmd = kmem_zalloc(cmd_len, KM_SLEEP);
2158 }
2159
2160 if ((resp_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2161 ASSERT(pkt->pkt_resp_dma != NULL);
2162
2163 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2164 fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2165 callback, NULL, (caddr_t *)&pkt->pkt_resp, &real_len,
2166 &pkt->pkt_resp_acc);
2167
2168 if (rval != DDI_SUCCESS) {
2169 (void) fc_ulp_uninit_packet(
2170 (opaque_t)pinfo->port_handle, pkt);
2171 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2172 fcsm_free_cmd_dma(cmd);
2173 return (NULL);
2174 }
2175
2176 cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_MEM;
2177
2178 if (real_len < resp_len) {
2179 (void) fc_ulp_uninit_packet(
2180 (opaque_t)pinfo->port_handle, pkt);
2181 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2182 fcsm_free_cmd_dma(cmd);
2183 return (NULL);
2184 }
2185
2186 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2187 pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
2188 callback, NULL, &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2189
2190 if (rval != DDI_DMA_MAPPED) {
2191 (void) fc_ulp_uninit_packet(
2192 (opaque_t)pinfo->port_handle, pkt);
2193 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2194 fcsm_free_cmd_dma(cmd);
2195 return (NULL);
2196 }
2197
2198 cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_BIND;
2199
2200 if (pkt->pkt_resp_cookie_cnt >
2201 pinfo->port_resp_dma_attr->dma_attr_sgllen) {
2202 (void) fc_ulp_uninit_packet(
2203 (opaque_t)pinfo->port_handle, pkt);
2204 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2205 fcsm_free_cmd_dma(cmd);
2206 return (NULL);
2207 }
2208
2209 ASSERT(pkt->pkt_resp_cookie_cnt != 0);
2210
2211 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2212 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2213 KM_NOSLEEP);
2214
2215 if (cp == NULL) {
2216 (void) fc_ulp_uninit_packet(
2217 (opaque_t)pinfo->port_handle, pkt);
2218 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2219 fcsm_free_cmd_dma(cmd);
2220 return (NULL);
2221 }
2222
2223 *cp = pkt_cookie;
2224 cp++;
2225 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2226 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2227 *cp = pkt_cookie;
2228 }
2229 } else if (resp_len != 0) {
2230 pkt->pkt_resp = kmem_zalloc(resp_len, KM_SLEEP);
2231 }
2232
2233 pkt->pkt_cmdlen = cmd_len;
2234 pkt->pkt_rsplen = resp_len;
2235
2236 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2237 "alloc_cmd: cmd 0x%p", (void *)cmd));
2238 return (cmd);
2239 }
2240
2241 static void
fcsm_free_cmd(fcsm_cmd_t * cmd)2242 fcsm_free_cmd(fcsm_cmd_t *cmd)
2243 {
2244 fcsm_t *fcsm;
2245
2246 fcsm = cmd->cmd_fcsm;
2247 ASSERT(fcsm != NULL);
2248
2249 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2250 "free_cmd: cmd 0x%p", (void *)cmd));
2251
2252 fcsm_free_cmd_dma(cmd);
2253
2254 (void) fc_ulp_uninit_packet((opaque_t)fcsm->sm_port_info.port_handle,
2255 cmd->cmd_fp_pkt);
2256 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2257 }
2258
2259 static void
fcsm_free_cmd_dma(fcsm_cmd_t * cmd)2260 fcsm_free_cmd_dma(fcsm_cmd_t *cmd)
2261 {
2262 fc_packet_t *pkt;
2263
2264 pkt = cmd->cmd_fp_pkt;
2265 ASSERT(pkt != NULL);
2266
2267 if (cmd->cmd_fcsm->sm_flags & FCSM_USING_NODMA_FCA) {
2268 if (pkt->pkt_cmd) {
2269 kmem_free(pkt->pkt_cmd, pkt->pkt_cmdlen);
2270 pkt->pkt_cmd = NULL;
2271 }
2272
2273 if (pkt->pkt_resp) {
2274 kmem_free(pkt->pkt_resp, pkt->pkt_rsplen);
2275 pkt->pkt_resp = NULL;
2276 }
2277 }
2278
2279 pkt->pkt_cmdlen = 0;
2280 pkt->pkt_rsplen = 0;
2281 pkt->pkt_tran_type = 0;
2282 pkt->pkt_tran_flags = 0;
2283
2284 if (pkt->pkt_cmd_cookie != NULL) {
2285 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2286 sizeof (ddi_dma_cookie_t));
2287 pkt->pkt_cmd_cookie = NULL;
2288 }
2289
2290 if (pkt->pkt_resp_cookie != NULL) {
2291 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2292 sizeof (ddi_dma_cookie_t));
2293 pkt->pkt_resp_cookie = NULL;
2294 }
2295
2296 if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_BIND) {
2297 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2298 }
2299
2300 if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_MEM) {
2301 if (pkt->pkt_cmd_acc) {
2302 ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2303 }
2304 }
2305
2306 if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_BIND) {
2307 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2308 }
2309
2310 if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_MEM) {
2311 if (pkt->pkt_resp_acc) {
2312 ddi_dma_mem_free(&pkt->pkt_resp_acc);
2313 }
2314 }
2315
2316 cmd->cmd_dma_flags = 0;
2317 }
2318
2319 /* ARGSUSED */
2320 static int
fcsm_job_cache_constructor(void * buf,void * cdarg,int kmflag)2321 fcsm_job_cache_constructor(void *buf, void *cdarg, int kmflag)
2322 {
2323 fcsm_job_t *job = (fcsm_job_t *)buf;
2324
2325 mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
2326 sema_init(&job->job_sema, 0, NULL, SEMA_DEFAULT, NULL);
2327
2328 return (0);
2329 }
2330
2331 /* ARGSUSED */
2332 static void
fcsm_job_cache_destructor(void * buf,void * cdarg)2333 fcsm_job_cache_destructor(void *buf, void *cdarg)
2334 {
2335 fcsm_job_t *job = (fcsm_job_t *)buf;
2336
2337 sema_destroy(&job->job_sema);
2338 mutex_destroy(&job->job_mutex);
2339 }
2340
2341
2342 static fcsm_job_t *
fcsm_alloc_job(int sleep)2343 fcsm_alloc_job(int sleep)
2344 {
2345 fcsm_job_t *job;
2346
2347 job = (fcsm_job_t *)kmem_cache_alloc(fcsm_job_cache, sleep);
2348 if (job != NULL) {
2349 job->job_code = FCSM_JOB_NONE;
2350 job->job_flags = 0;
2351 job->job_port_instance = -1;
2352 job->job_result = -1;
2353 job->job_arg = (opaque_t)0;
2354 job->job_caller_priv = (opaque_t)0;
2355 job->job_comp = NULL;
2356 job->job_comp_arg = (opaque_t)0;
2357 job->job_priv = (void *)0;
2358 job->job_priv_flags = 0;
2359 job->job_next = 0;
2360 }
2361
2362 return (job);
2363 }
2364
2365 static void
fcsm_dealloc_job(fcsm_job_t * job)2366 fcsm_dealloc_job(fcsm_job_t *job)
2367 {
2368 kmem_cache_free(fcsm_job_cache, (void *)job);
2369 }
2370
2371
2372 static void
fcsm_init_job(fcsm_job_t * job,int instance,uint32_t command,uint32_t flags,opaque_t arg,opaque_t caller_priv,void (* comp)(opaque_t,fcsm_job_t *,int),opaque_t comp_arg)2373 fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags,
2374 opaque_t arg, opaque_t caller_priv,
2375 void (*comp)(opaque_t, fcsm_job_t *, int), opaque_t comp_arg)
2376 {
2377 ASSERT(job != NULL);
2378 job->job_port_instance = instance;
2379 job->job_code = command;
2380 job->job_flags = flags;
2381 job->job_arg = arg;
2382 job->job_caller_priv = caller_priv;
2383 job->job_comp = comp;
2384 job->job_comp_arg = comp_arg;
2385 job->job_retry_count = 0;
2386 }
2387
2388 static int
fcsm_process_job(fcsm_job_t * job,int priority_flag)2389 fcsm_process_job(fcsm_job_t *job, int priority_flag)
2390 {
2391 fcsm_t *fcsm;
2392 int sync;
2393
2394 ASSERT(job != NULL);
2395 ASSERT(!MUTEX_HELD(&job->job_mutex));
2396
2397 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2398
2399 if (fcsm == NULL) {
2400 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
2401 "process_job: port instance 0x%x not found",
2402 job->job_port_instance));
2403 return (FC_BADDEV);
2404 }
2405
2406 mutex_enter(&job->job_mutex);
2407 /* Both SYNC and ASYNC flags should not be set */
2408 ASSERT(((job->job_flags & (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) ==
2409 FCSM_JOBFLAG_SYNC) || ((job->job_flags &
2410 (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == FCSM_JOBFLAG_ASYNC));
2411 /*
2412 * Check if job is a synchronous job. We might not be able to
2413 * check it reliably after enque_job(), if job is an ASYNC job.
2414 */
2415 sync = job->job_flags & FCSM_JOBFLAG_SYNC;
2416 mutex_exit(&job->job_mutex);
2417
2418 /* Queue the job for processing by job thread */
2419 fcsm_enque_job(fcsm, job, priority_flag);
2420
2421 /* Wait for job completion, if it is a synchronous job */
2422 if (sync) {
2423 /*
2424 * This is a Synchronous Job. So job structure is available.
2425 * Caller is responsible for freeing it.
2426 */
2427 FCSM_DEBUG(SMDL_ERR, (CE_CONT, SM_LOG, fcsm, NULL,
2428 "process_job: Waiting for sync job <%p> completion",
2429 (void *)job));
2430 sema_p(&job->job_sema);
2431 }
2432
2433 return (FC_SUCCESS);
2434 }
2435
2436 static void
fcsm_enque_job(fcsm_t * fcsm,fcsm_job_t * job,int priority_flag)2437 fcsm_enque_job(fcsm_t *fcsm, fcsm_job_t *job, int priority_flag)
2438 {
2439 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
2440
2441 mutex_enter(&fcsm->sm_mutex);
2442 /* Queue the job at the head or tail depending on the job priority */
2443 if (priority_flag) {
2444 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2445 "enque_job: job 0x%p is high priority", job));
2446 /* Queue at the head */
2447 if (fcsm->sm_job_tail == NULL) {
2448 ASSERT(fcsm->sm_job_head == NULL);
2449 fcsm->sm_job_head = fcsm->sm_job_tail = job;
2450 } else {
2451 ASSERT(fcsm->sm_job_head != NULL);
2452 job->job_next = fcsm->sm_job_head;
2453 fcsm->sm_job_head = job;
2454 }
2455 } else {
2456 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2457 "enque_job: job 0x%p is normal", job));
2458 /* Queue at the tail */
2459 if (fcsm->sm_job_tail == NULL) {
2460 ASSERT(fcsm->sm_job_head == NULL);
2461 fcsm->sm_job_head = fcsm->sm_job_tail = job;
2462 } else {
2463 ASSERT(fcsm->sm_job_head != NULL);
2464 fcsm->sm_job_tail->job_next = job;
2465 fcsm->sm_job_tail = job;
2466 }
2467 job->job_next = NULL;
2468 }
2469
2470 /* Signal the job thread to process the job */
2471 cv_signal(&fcsm->sm_job_cv);
2472 mutex_exit(&fcsm->sm_mutex);
2473 }
2474
2475 static int
fcsm_retry_job(fcsm_t * fcsm,fcsm_job_t * job)2476 fcsm_retry_job(fcsm_t *fcsm, fcsm_job_t *job)
2477 {
2478 /*
2479 * If it is a CT passthru job and status is login required, then
2480 * retry the job so that login can be performed again.
2481 * Ensure that this retry is performed a finite number of times,
2482 * so that a faulty fabric does not cause us to retry forever.
2483 */
2484
2485 switch (job->job_code) {
2486 case FCSM_JOB_CT_PASSTHRU: {
2487 uint32_t jobflag;
2488 fc_ct_header_t *ct_header;
2489
2490 if (job->job_result != FC_LOGINREQ) {
2491 break;
2492 }
2493
2494 /*
2495 * If it is a management server command
2496 * then Reset the Management server login flag, so that login
2497 * gets re-established.
2498 * If it is a Name server command,
2499 * then it is 'fp' responsibility to perform the login.
2500 */
2501 ASSERT(job->job_arg != NULL);
2502 ct_header =
2503 (fc_ct_header_t *)((fcio_t *)job->job_arg)->fcio_ibuf;
2504 if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2505 mutex_enter(&fcsm->sm_mutex);
2506 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
2507 mutex_exit(&fcsm->sm_mutex);
2508 }
2509
2510 if (job->job_retry_count >= fcsm_max_job_retries) {
2511 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2512 "retry_job: job 0x%p max retries (%d) reached",
2513 (void *)job, job->job_retry_count));
2514 break;
2515 }
2516
2517 /*
2518 * Login is required again. Retry the command, so that
2519 * login will get performed again.
2520 */
2521 mutex_enter(&job->job_mutex);
2522 job->job_retry_count++;
2523 jobflag = job->job_flags;
2524 mutex_exit(&job->job_mutex);
2525
2526 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2527 "retry_job: retry(%d) job 0x%p",
2528 job->job_retry_count, (void *)job));
2529 /*
2530 * This job should get picked up before the
2531 * other jobs sitting in the queue.
2532 * Requeue the command at the head and then
2533 * reset the SERIALIZE flag.
2534 */
2535 fcsm_enque_job(fcsm, job, 1);
2536 if (jobflag & FCSM_JOBFLAG_SERIALIZE) {
2537 mutex_enter(&fcsm->sm_mutex);
2538 ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2539 fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2540
2541 /* Signal the job thread to process the job */
2542 cv_signal(&fcsm->sm_job_cv);
2543 mutex_exit(&fcsm->sm_mutex);
2544 }
2545
2546 /* Command is queued for retrying */
2547 return (0);
2548 }
2549
2550 default:
2551 break;
2552 }
2553 return (1);
2554 }
2555
2556 static void
fcsm_jobdone(fcsm_job_t * job)2557 fcsm_jobdone(fcsm_job_t *job)
2558 {
2559 fcsm_t *fcsm;
2560
2561 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2562 ASSERT(fcsm != NULL);
2563
2564 if (job->job_result != FC_SUCCESS) {
2565 if (fcsm_retry_job(fcsm, job) == 0) {
2566 /* Job retried. so just return from here */
2567 return;
2568 }
2569 }
2570
2571 if (job->job_comp) {
2572 job->job_comp(job->job_comp_arg, job, job->job_result);
2573 }
2574
2575 mutex_enter(&job->job_mutex);
2576 if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2577 mutex_exit(&job->job_mutex);
2578 mutex_enter(&fcsm->sm_mutex);
2579 ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2580 fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2581
2582 /* Signal the job thread to process the job */
2583 cv_signal(&fcsm->sm_job_cv);
2584 mutex_exit(&fcsm->sm_mutex);
2585 mutex_enter(&job->job_mutex);
2586 }
2587
2588 if (job->job_flags & FCSM_JOBFLAG_SYNC) {
2589 mutex_exit(&job->job_mutex);
2590 sema_v(&job->job_sema);
2591 } else {
2592 mutex_exit(&job->job_mutex);
2593 /* Async job, free the job structure */
2594 fcsm_dealloc_job(job);
2595 }
2596 }
2597
2598 fcsm_job_t *
fcsm_deque_job(fcsm_t * fcsm)2599 fcsm_deque_job(fcsm_t *fcsm)
2600 {
2601 fcsm_job_t *job;
2602
2603 ASSERT(MUTEX_HELD(&fcsm->sm_mutex));
2604
2605 if (fcsm->sm_job_head == NULL) {
2606 ASSERT(fcsm->sm_job_tail == NULL);
2607 job = NULL;
2608 } else {
2609 ASSERT(fcsm->sm_job_tail != NULL);
2610 job = fcsm->sm_job_head;
2611 if (job->job_next == NULL) {
2612 ASSERT(fcsm->sm_job_tail == job);
2613 fcsm->sm_job_tail = NULL;
2614 }
2615 fcsm->sm_job_head = job->job_next;
2616 job->job_next = NULL;
2617 }
2618
2619 return (job);
2620 }
2621
2622
2623 /* Dedicated per port thread to process various commands */
2624 static void
fcsm_job_thread(fcsm_t * fcsm)2625 fcsm_job_thread(fcsm_t *fcsm)
2626 {
2627 fcsm_job_t *job;
2628
2629 ASSERT(fcsm != NULL);
2630 #ifndef __lock_lint
2631 CALLB_CPR_INIT(&fcsm->sm_cpr_info, &fcsm->sm_mutex,
2632 callb_generic_cpr, "fcsm_job_thread");
2633 #endif /* __lock_lint */
2634
2635 for (;;) {
2636 mutex_enter(&fcsm->sm_mutex);
2637
2638 while (fcsm->sm_job_head == NULL ||
2639 fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD) {
2640 CALLB_CPR_SAFE_BEGIN(&fcsm->sm_cpr_info);
2641 cv_wait(&fcsm->sm_job_cv, &fcsm->sm_mutex);
2642 CALLB_CPR_SAFE_END(&fcsm->sm_cpr_info, &fcsm->sm_mutex);
2643 }
2644
2645 job = fcsm_deque_job(fcsm);
2646
2647 mutex_exit(&fcsm->sm_mutex);
2648
2649 mutex_enter(&job->job_mutex);
2650 if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2651 mutex_exit(&job->job_mutex);
2652
2653 mutex_enter(&fcsm->sm_mutex);
2654 ASSERT(!(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD));
2655 fcsm->sm_flags |= FCSM_SERIALIZE_JOBTHREAD;
2656 mutex_exit(&fcsm->sm_mutex);
2657 } else {
2658 mutex_exit(&job->job_mutex);
2659 }
2660
2661 ASSERT(fcsm->sm_instance == job->job_port_instance);
2662
2663 switch (job->job_code) {
2664 case FCSM_JOB_NONE:
2665 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
2666 "job_thread: uninitialized job code");
2667 job->job_result = FC_FAILURE;
2668 fcsm_jobdone(job);
2669 break;
2670
2671 case FCSM_JOB_THREAD_SHUTDOWN:
2672 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2673 "job_thread: job code <JOB PORT SHUTDOWN>"));
2674
2675 /*
2676 * There should not be any pending jobs, when this
2677 * is being called.
2678 */
2679 mutex_enter(&fcsm->sm_mutex);
2680 ASSERT(fcsm->sm_job_head == NULL);
2681 ASSERT(fcsm->sm_job_tail == NULL);
2682 ASSERT(fcsm->sm_retry_head == NULL);
2683 ASSERT(fcsm->sm_retry_tail == NULL);
2684 job->job_result = FC_SUCCESS;
2685 #ifndef __lock_lint
2686 CALLB_CPR_EXIT(&fcsm->sm_cpr_info);
2687 #endif
2688 /* CPR_EXIT has also dropped the fcsm->sm_mutex */
2689
2690 fcsm_jobdone(job);
2691 thread_exit();
2692 /* NOTREACHED */
2693 break;
2694
2695 case FCSM_JOB_LOGIN_NAME_SERVER:
2696 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2697 "job_thread: job code <LOGIN_NAME_SERVER>"));
2698 job->job_result = FC_SUCCESS;
2699 fcsm_jobdone(job);
2700 break;
2701
2702 case FCSM_JOB_LOGIN_MGMT_SERVER:
2703 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2704 "job_thread: job code <LOGIN_MGMT_SERVER>"));
2705 fcsm_job_login_mgmt_server(job);
2706 break;
2707
2708 case FCSM_JOB_CT_PASSTHRU:
2709 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2710 "job_thread: job code <CT_PASSTHRU>"));
2711 fcsm_job_ct_passthru(job);
2712 break;
2713
2714 default:
2715 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2716 "job_thread: job code <UNKNOWN>"));
2717 job->job_result = FC_FAILURE;
2718 fcsm_jobdone(job);
2719 break;
2720 }
2721 }
2722
2723 /* NOTREACHED */
2724 }
2725
2726
2727 static void
fcsm_ct_init(fcsm_t * fcsm,fcsm_cmd_t * cmd,fc_ct_aiu_t * req_iu,size_t req_len,void (* comp_func)())2728 fcsm_ct_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, fc_ct_aiu_t *req_iu, size_t req_len,
2729 void (*comp_func)())
2730 {
2731 fc_packet_t *pkt;
2732
2733 pkt = cmd->cmd_fp_pkt;
2734 ASSERT(pkt != NULL);
2735
2736 ASSERT(req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE ||
2737 (req_iu->aiu_header.ct_fcstype == FCSTYPE_DIRECTORY &&
2738 req_iu->aiu_header.ct_fcssubtype == FCSSUB_DS_NAME_SERVER));
2739
2740
2741 /* Set the pkt d_id properly */
2742 if (req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE) {
2743 pkt->pkt_cmd_fhdr.d_id = FS_MANAGEMENT_SERVER;
2744 } else {
2745 pkt->pkt_cmd_fhdr.d_id = FS_NAME_SERVER;
2746 }
2747
2748 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
2749 pkt->pkt_cmd_fhdr.rsvd = 0;
2750 pkt->pkt_cmd_fhdr.s_id = fcsm->sm_sid;
2751 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
2752 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
2753 F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
2754 pkt->pkt_cmd_fhdr.seq_id = 0;
2755 pkt->pkt_cmd_fhdr.df_ctl = 0;
2756 pkt->pkt_cmd_fhdr.seq_cnt = 0;
2757 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
2758 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
2759 pkt->pkt_cmd_fhdr.ro = 0;
2760
2761 pkt->pkt_timeout = FCSM_MS_TIMEOUT;
2762 pkt->pkt_comp = comp_func;
2763
2764 FCSM_REP_WR(pkt->pkt_cmd_acc, req_iu, pkt->pkt_cmd, req_len);
2765
2766 cmd->cmd_transport = fc_ulp_transport;
2767 }
2768
2769 static void
fcsm_ct_intr(fcsm_cmd_t * cmd)2770 fcsm_ct_intr(fcsm_cmd_t *cmd)
2771 {
2772 fc_packet_t *pkt;
2773 fcsm_job_t *job;
2774 fcio_t *fcio;
2775 fcsm_t *fcsm;
2776
2777 pkt = cmd->cmd_fp_pkt;
2778 job = cmd->cmd_job;
2779 ASSERT(job != NULL);
2780
2781 fcio = job->job_arg;
2782 ASSERT(fcio != NULL);
2783
2784 if (pkt->pkt_state != FC_PKT_SUCCESS) {
2785 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
2786 "ct_intr: CT command <0x%x> to did 0x%x failed",
2787 ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp,
2788 pkt->pkt_cmd_fhdr.d_id));
2789 } else {
2790 /* Get the CT response payload */
2791 fcsm = cmd->cmd_fcsm;
2792 FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
2793 pkt->pkt_resp, fcio->fcio_olen);
2794 }
2795
2796 job->job_result =
2797 fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
2798
2799 fcsm_free_cmd(cmd);
2800
2801 fcsm_jobdone(job);
2802 }
2803
2804
2805 static void
fcsm_job_ct_passthru(fcsm_job_t * job)2806 fcsm_job_ct_passthru(fcsm_job_t *job)
2807 {
2808 fcsm_t *fcsm;
2809 fcio_t *fcio;
2810 fcsm_cmd_t *cmd;
2811 int status;
2812 fc_ct_header_t *ct_header;
2813
2814 ASSERT(job != NULL);
2815 ASSERT(job->job_port_instance != -1);
2816
2817 job->job_result = FC_FAILURE;
2818 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2819 if (fcsm == NULL) {
2820 fcsm_jobdone(job);
2821 return;
2822 }
2823
2824 /*
2825 * Process the CT Passthru job only if port is attached
2826 * to a FABRIC.
2827 */
2828 if (!FC_TOP_EXTERNAL(fcsm->sm_port_top)) {
2829 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2830 "job_ct_passthru: end (non-fabric port)"));
2831 job->job_result = FC_BADDEV;
2832 fcsm_jobdone(job);
2833 return;
2834 }
2835
2836 fcio = job->job_arg;
2837 ASSERT(fcio != NULL);
2838
2839 /*
2840 * If it is NOT a Management Seriver (MS) or Name Server (NS) command
2841 * then complete the command with failure.
2842 */
2843 ct_header = (fc_ct_header_t *)fcio->fcio_ibuf;
2844
2845 /*
2846 * According to libHBAAPI spec, CT header from libHBAAPI would always
2847 * be big endian, so we must swap CT header before continue in little
2848 * endian platforms.
2849 */
2850 mutex_enter(&job->job_mutex);
2851 if (!(job->job_flags & FCSM_JOBFLAG_CTHEADER_BE)) {
2852 job->job_flags |= FCSM_JOBFLAG_CTHEADER_BE;
2853 *((uint32_t *)((uint32_t *)ct_header + 0)) =
2854 BE_32(*((uint32_t *)((uint32_t *)ct_header + 0)));
2855 *((uint32_t *)((uint32_t *)ct_header + 1)) =
2856 BE_32(*((uint32_t *)((uint32_t *)ct_header + 1)));
2857 *((uint32_t *)((uint32_t *)ct_header + 2)) =
2858 BE_32(*((uint32_t *)((uint32_t *)ct_header + 2)));
2859 *((uint32_t *)((uint32_t *)ct_header + 3)) =
2860 BE_32(*((uint32_t *)((uint32_t *)ct_header + 3)));
2861 }
2862 mutex_exit(&job->job_mutex);
2863
2864 if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2865 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2866 "job_ct_passthru: Management Server Cmd"));
2867 } else if (ct_header->ct_fcstype == FCSTYPE_DIRECTORY) {
2868 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2869 "job_ct_passthru: Name Server Cmd"));
2870 } else {
2871 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2872 "job_ct_passthru: Unsupported Destination "
2873 "gs_type <0x%x> gs_subtype <0x%x>",
2874 ct_header->ct_fcstype, ct_header->ct_fcssubtype));
2875 }
2876
2877 if (ct_header->ct_fcstype != FCSTYPE_MGMTSERVICE &&
2878 (ct_header->ct_fcstype != FCSTYPE_DIRECTORY ||
2879 ct_header->ct_fcssubtype != FCSSUB_DS_NAME_SERVER)) {
2880 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2881 "job_ct_passthru: end (Not a Name Server OR "
2882 "Mgmt Server Cmd)"));
2883 job->job_result = FC_BADCMD;
2884 fcsm_jobdone(job);
2885 return;
2886 }
2887
2888 /*
2889 * If it is an MS command and we are not logged in to the management
2890 * server, then start the login and requeue the command.
2891 * If login to management server is in progress, then reque the
2892 * command to wait for login to complete.
2893 */
2894 mutex_enter(&fcsm->sm_mutex);
2895 if ((ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) &&
2896 !(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN)) {
2897 mutex_exit(&fcsm->sm_mutex);
2898 if (fcsm_login_and_process_job(fcsm, job) != FC_SUCCESS) {
2899 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2900 "job_ct_passthru: perform login failed"));
2901 job->job_result = FC_FAILURE;
2902 fcsm_jobdone(job);
2903 }
2904 return;
2905 }
2906 mutex_exit(&fcsm->sm_mutex);
2907
2908 /*
2909 * We are already logged in to the management server.
2910 * Issue the CT Passthru command
2911 */
2912 cmd = fcsm_alloc_cmd(fcsm, fcio->fcio_ilen, fcio->fcio_olen, KM_SLEEP);
2913 if (cmd == NULL) {
2914 job->job_result = FC_NOMEM;
2915 fcsm_jobdone(job);
2916 return;
2917 }
2918
2919 FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
2920 fcsm_max_cmd_retries, fcsm_ct_intr);
2921
2922 fcsm_ct_init(fcsm, cmd, (fc_ct_aiu_t *)fcio->fcio_ibuf, fcio->fcio_ilen,
2923 fcsm_pkt_common_intr);
2924
2925 if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
2926 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
2927 "job_ct_passthru: issue CT Passthru failed, status 0x%x",
2928 status));
2929 job->job_result = status;
2930 fcsm_free_cmd(cmd);
2931 fcsm_jobdone(job);
2932 return;
2933 }
2934 }
2935
2936 static int
fcsm_login_and_process_job(fcsm_t * fcsm,fcsm_job_t * orig_job)2937 fcsm_login_and_process_job(fcsm_t *fcsm, fcsm_job_t *orig_job)
2938 {
2939 fcsm_job_t *login_job;
2940 #ifdef DEBUG
2941 int status;
2942 #endif /* DEBUG */
2943
2944 if (orig_job->job_code != FCSM_JOB_CT_PASSTHRU) {
2945 return (FC_FAILURE);
2946 }
2947
2948 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2949 "login_and_process_job: start login."));
2950
2951 mutex_enter(&fcsm->sm_mutex);
2952 if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) {
2953 /*
2954 * Directory server login completed just now, while the
2955 * mutex was dropped. Just queue the command again for
2956 * processing.
2957 */
2958 mutex_exit(&fcsm->sm_mutex);
2959 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2960 "login_and_process_job: got job 0x%p. login just "
2961 "completed", (void *)orig_job));
2962 fcsm_enque_job(fcsm, orig_job, 0);
2963 return (FC_SUCCESS);
2964 }
2965
2966 if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG) {
2967 /*
2968 * Ideally we shouldn't have come here, since login
2969 * job has the serialize flag set.
2970 * Anyway, put the command back on the queue.
2971 */
2972 mutex_exit(&fcsm->sm_mutex);
2973 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2974 "login_and_process_job: got job 0x%p while login to "
2975 "management server in progress", (void *)orig_job));
2976 fcsm_enque_job(fcsm, orig_job, 0);
2977 return (FC_SUCCESS);
2978 }
2979
2980 fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGIN_IN_PROG;
2981 mutex_exit(&fcsm->sm_mutex);
2982
2983 login_job = fcsm_alloc_job(KM_SLEEP);
2984 ASSERT(login_job != NULL);
2985
2986 /*
2987 * Mark the login job as SERIALIZE, so that all other jobs will
2988 * be processed after completing the login.
2989 * Save the original job (CT Passthru job) in the caller private
2990 * field in the job structure, so that CT command can be issued
2991 * after login has completed.
2992 */
2993 fcsm_init_job(login_job, fcsm->sm_instance, FCSM_JOB_LOGIN_MGMT_SERVER,
2994 FCSM_JOBFLAG_ASYNC | FCSM_JOBFLAG_SERIALIZE,
2995 (opaque_t)NULL, (opaque_t)orig_job, fcsm_login_ms_comp, NULL);
2996 orig_job->job_priv = (void *)login_job;
2997
2998 #ifdef DEBUG
2999 status = fcsm_process_job(login_job, 1);
3000 ASSERT(status == FC_SUCCESS);
3001 #else /* DEBUG */
3002 (void) fcsm_process_job(login_job, 1);
3003 #endif /* DEBUG */
3004 return (FC_SUCCESS);
3005 }
3006
3007
3008 /* ARGSUSED */
3009 static void
fcsm_login_ms_comp(opaque_t comp_arg,fcsm_job_t * login_job,int result)3010 fcsm_login_ms_comp(opaque_t comp_arg, fcsm_job_t *login_job, int result)
3011 {
3012 fcsm_t *fcsm;
3013 fcsm_job_t *orig_job;
3014
3015 ASSERT(login_job != NULL);
3016
3017 orig_job = (fcsm_job_t *)login_job->job_caller_priv;
3018
3019 ASSERT(orig_job != NULL);
3020 ASSERT(orig_job->job_priv == (void *)login_job);
3021 orig_job->job_priv = NULL;
3022
3023 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3024 "login_ms_comp: result 0x%x", login_job->job_result));
3025
3026 /* Set the login flag in the per port fcsm structure */
3027 ASSERT(login_job->job_port_instance == orig_job->job_port_instance);
3028 fcsm = ddi_get_soft_state(fcsm_state, login_job->job_port_instance);
3029 ASSERT(fcsm != NULL);
3030
3031 mutex_enter(&fcsm->sm_mutex);
3032 ASSERT((fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) == 0);
3033 ASSERT(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG);
3034 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG;
3035 if (login_job->job_result != FC_SUCCESS) {
3036 caddr_t msg;
3037
3038 /*
3039 * Login failed. Complete the original job with FC_LOGINREQ
3040 * status. Retry of that job will cause login to be
3041 * retried.
3042 */
3043 mutex_exit(&fcsm->sm_mutex);
3044 orig_job->job_result = FC_LOGINREQ;
3045 fcsm_jobdone(orig_job);
3046
3047 (void) fc_ulp_error(login_job->job_result, &msg);
3048 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
3049 "login_ms_comp: Management server login failed: <%s>", msg);
3050 return;
3051 }
3052 fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGGED_IN;
3053 mutex_exit(&fcsm->sm_mutex);
3054
3055 /*
3056 * Queue the original job at the head of the queue for processing.
3057 */
3058 fcsm_enque_job(fcsm, orig_job, 1);
3059 }
3060
3061
3062 static void
fcsm_els_init(fcsm_cmd_t * cmd,uint32_t d_id)3063 fcsm_els_init(fcsm_cmd_t *cmd, uint32_t d_id)
3064 {
3065 fc_packet_t *pkt;
3066 fcsm_t *fcsm;
3067
3068 fcsm = cmd->cmd_fcsm;
3069 pkt = cmd->cmd_fp_pkt;
3070 ASSERT(fcsm != NULL && pkt != NULL);
3071
3072 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3073 pkt->pkt_cmd_fhdr.d_id = d_id;
3074 pkt->pkt_cmd_fhdr.rsvd = 0;
3075 pkt->pkt_cmd_fhdr.s_id = fcsm->sm_sid;
3076 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3077 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
3078 pkt->pkt_cmd_fhdr.seq_id = 0;
3079 pkt->pkt_cmd_fhdr.df_ctl = 0;
3080 pkt->pkt_cmd_fhdr.seq_cnt = 0;
3081 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
3082 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
3083 pkt->pkt_cmd_fhdr.ro = 0;
3084
3085 pkt->pkt_timeout = FCSM_ELS_TIMEOUT;
3086 }
3087
3088
3089 static int
fcsm_xlogi_init(fcsm_t * fcsm,fcsm_cmd_t * cmd,uint32_t d_id,void (* comp_func)(),uchar_t ls_code)3090 fcsm_xlogi_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, uint32_t d_id,
3091 void (*comp_func)(), uchar_t ls_code)
3092 {
3093 ls_code_t payload;
3094 fc_packet_t *pkt;
3095 la_els_logi_t *login_params;
3096 int status;
3097
3098 login_params = (la_els_logi_t *)
3099 kmem_zalloc(sizeof (la_els_logi_t), KM_SLEEP);
3100 if (login_params == NULL) {
3101 return (FC_NOMEM);
3102 }
3103
3104 status = fc_ulp_get_port_login_params(fcsm->sm_port_info.port_handle,
3105 login_params);
3106 if (status != FC_SUCCESS) {
3107 kmem_free(login_params, sizeof (la_els_logi_t));
3108 return (status);
3109 }
3110
3111 pkt = cmd->cmd_fp_pkt;
3112
3113 fcsm_els_init(cmd, d_id);
3114 pkt->pkt_comp = comp_func;
3115
3116 payload.ls_code = ls_code;
3117 payload.mbz = 0;
3118
3119 FCSM_REP_WR(pkt->pkt_cmd_acc, login_params,
3120 pkt->pkt_cmd, sizeof (la_els_logi_t));
3121 FCSM_REP_WR(pkt->pkt_cmd_acc, &payload,
3122 pkt->pkt_cmd, sizeof (payload));
3123
3124 cmd->cmd_transport = fc_ulp_issue_els;
3125
3126 kmem_free(login_params, sizeof (la_els_logi_t));
3127
3128 return (FC_SUCCESS);
3129 }
3130
3131 static void
fcsm_xlogi_intr(fcsm_cmd_t * cmd)3132 fcsm_xlogi_intr(fcsm_cmd_t *cmd)
3133 {
3134 fc_packet_t *pkt;
3135 fcsm_job_t *job;
3136 fcsm_t *fcsm;
3137
3138 pkt = cmd->cmd_fp_pkt;
3139 job = cmd->cmd_job;
3140 ASSERT(job != NULL);
3141
3142 fcsm = cmd->cmd_fcsm;
3143 ASSERT(fcsm != NULL);
3144
3145 if (pkt->pkt_state != FC_PKT_SUCCESS) {
3146 fcsm_display(CE_WARN, SM_LOG, fcsm, pkt,
3147 "xlogi_intr: login to DID 0x%x failed",
3148 pkt->pkt_cmd_fhdr.d_id);
3149 } else {
3150 /* Get the Login parameters of the Management Server */
3151 FCSM_REP_RD(pkt->pkt_resp_acc, &fcsm->sm_ms_service_params,
3152 pkt->pkt_resp, sizeof (la_els_logi_t));
3153 }
3154
3155 job->job_result =
3156 fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3157
3158 fcsm_free_cmd(cmd);
3159
3160 fcsm_jobdone(job);
3161 }
3162
3163 static void
fcsm_job_login_mgmt_server(fcsm_job_t * job)3164 fcsm_job_login_mgmt_server(fcsm_job_t *job)
3165 {
3166 fcsm_t *fcsm;
3167 fcsm_cmd_t *cmd;
3168 int status;
3169
3170 ASSERT(job != NULL);
3171 ASSERT(job->job_port_instance != -1);
3172
3173 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
3174 if (fcsm == NULL) {
3175 job->job_result = FC_NOMEM;
3176 fcsm_jobdone(job);
3177 return;
3178 }
3179
3180 /*
3181 * Issue the Login command to the management server.
3182 */
3183 cmd = fcsm_alloc_cmd(fcsm, sizeof (la_els_logi_t),
3184 sizeof (la_els_logi_t), KM_SLEEP);
3185 if (cmd == NULL) {
3186 job->job_result = FC_NOMEM;
3187 fcsm_jobdone(job);
3188 return;
3189 }
3190
3191 FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
3192 fcsm_max_cmd_retries, fcsm_xlogi_intr);
3193
3194 status = fcsm_xlogi_init(fcsm, cmd, FS_MANAGEMENT_SERVER,
3195 fcsm_pkt_common_intr, LA_ELS_PLOGI);
3196
3197 if (status != FC_SUCCESS) {
3198 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3199 "job_login_mgmt_server: plogi init failed. status 0x%x",
3200 status));
3201 job->job_result = status;
3202 fcsm_free_cmd(cmd);
3203 fcsm_jobdone(job);
3204 return;
3205 }
3206
3207 if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
3208 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3209 "job_ct_passthru: issue login cmd failed, status 0x%x",
3210 status));
3211 job->job_result = status;
3212 fcsm_free_cmd(cmd);
3213 fcsm_jobdone(job);
3214 return;
3215 }
3216 }
3217
3218
3219 int
fcsm_ct_passthru(int instance,fcio_t * fcio,int sleep,int job_flags,void (* func)(fcio_t *))3220 fcsm_ct_passthru(int instance, fcio_t *fcio, int sleep, int job_flags,
3221 void (*func)(fcio_t *))
3222 {
3223 fcsm_job_t *job;
3224 int status;
3225
3226 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3227 "ct_passthru: instance 0x%x fcio 0x%p", instance, fcio));
3228 job = fcsm_alloc_job(sleep);
3229 ASSERT(sleep == KM_NOSLEEP || job != NULL);
3230
3231 fcsm_init_job(job, instance, FCSM_JOB_CT_PASSTHRU, job_flags,
3232 (opaque_t)fcio, (opaque_t)func, fcsm_ct_passthru_comp, NULL);
3233 status = fcsm_process_job(job, 0);
3234 if (status != FC_SUCCESS) {
3235 /* Job could not be issued. So free the job and return */
3236 fcsm_dealloc_job(job);
3237 return (status);
3238 }
3239
3240 if (job_flags & FCSM_JOBFLAG_SYNC) {
3241 status = job->job_result;
3242 fcsm_dealloc_job(job);
3243 }
3244
3245 return (status);
3246 }
3247
3248
3249 /* ARGSUSED */
3250 static void
fcsm_ct_passthru_comp(opaque_t comp_arg,fcsm_job_t * job,int result)3251 fcsm_ct_passthru_comp(opaque_t comp_arg, fcsm_job_t *job, int result)
3252 {
3253 ASSERT(job != NULL);
3254 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3255 "ct_passthru_comp: result 0x%x port 0x%x",
3256 job->job_result, job->job_port_instance));
3257 }
3258
3259
3260 static void
fcsm_pkt_common_intr(fc_packet_t * pkt)3261 fcsm_pkt_common_intr(fc_packet_t *pkt)
3262 {
3263 fcsm_cmd_t *cmd;
3264 int jobstatus;
3265 fcsm_t *fcsm;
3266
3267 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3268 "pkt_common_intr"));
3269
3270 cmd = (fcsm_cmd_t *)pkt->pkt_ulp_private;
3271 ASSERT(cmd != NULL);
3272
3273 if (pkt->pkt_state == FC_PKT_SUCCESS) {
3274 /* Command completed successfully. Just complete the command */
3275 cmd->cmd_comp(cmd);
3276 return;
3277 }
3278
3279 fcsm = cmd->cmd_fcsm;
3280 ASSERT(fcsm != NULL);
3281
3282 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
3283 "fc packet to DID 0x%x failed for pkt 0x%p",
3284 pkt->pkt_cmd_fhdr.d_id, pkt));
3285
3286 mutex_enter(&fcsm->sm_mutex);
3287 if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3288 /*
3289 * No need to retry the command. The link previously
3290 * suffered an offline timeout.
3291 */
3292 mutex_exit(&fcsm->sm_mutex);
3293 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3294 "pkt_common_intr: end. Link is down"));
3295 cmd->cmd_comp(cmd);
3296 return;
3297 }
3298 mutex_exit(&fcsm->sm_mutex);
3299
3300 jobstatus = fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3301 if (jobstatus == FC_LOGINREQ) {
3302 /*
3303 * Login to the destination is required. No need to
3304 * retry this cmd again.
3305 */
3306 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3307 "pkt_common_intr: end. LOGIN required"));
3308 cmd->cmd_comp(cmd);
3309 return;
3310 }
3311
3312 switch (pkt->pkt_state) {
3313 case FC_PKT_PORT_OFFLINE:
3314 case FC_PKT_LOCAL_RJT:
3315 case FC_PKT_TIMEOUT: {
3316 uchar_t pkt_state;
3317
3318 pkt_state = pkt->pkt_state;
3319 cmd->cmd_retry_interval = fcsm_retry_interval;
3320 if (fcsm_retry_cmd(cmd) != 0) {
3321 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3322 cmd->cmd_fcsm, NULL,
3323 "common_intr: max retries(%d) reached, status 0x%x",
3324 cmd->cmd_retry_count));
3325
3326 /*
3327 * Restore the pkt_state to the actual failure status
3328 * received at the time of pkt completion.
3329 */
3330 pkt->pkt_state = pkt_state;
3331 pkt->pkt_reason = 0;
3332 cmd->cmd_comp(cmd);
3333 } else {
3334 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3335 cmd->cmd_fcsm, NULL,
3336 "pkt_common_intr: retry(%d) on pkt state (0x%x)",
3337 cmd->cmd_retry_count, pkt_state));
3338 }
3339 break;
3340 }
3341 default:
3342 cmd->cmd_comp(cmd);
3343 break;
3344 }
3345 }
3346
3347 static int
fcsm_issue_cmd(fcsm_cmd_t * cmd)3348 fcsm_issue_cmd(fcsm_cmd_t *cmd)
3349 {
3350 fc_packet_t *pkt;
3351 fcsm_t *fcsm;
3352 int status;
3353
3354 pkt = cmd->cmd_fp_pkt;
3355 fcsm = cmd->cmd_fcsm;
3356
3357 /* Explicitly invalidate this field till fcsm decides to use it */
3358 pkt->pkt_ulp_rscn_infop = NULL;
3359
3360 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3361 "issue_cmd: entry"));
3362
3363 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3364 mutex_enter(&fcsm->sm_mutex);
3365 if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3366 /*
3367 * Update the pkt_state/pkt_reason appropriately.
3368 * Caller of this function can decide whether to call
3369 * 'pkt->pkt_comp' or use the 'status' returned by this func.
3370 */
3371 mutex_exit(&fcsm->sm_mutex);
3372 pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3373 pkt->pkt_reason = FC_REASON_OFFLINE;
3374 return (FC_OFFLINE);
3375 }
3376 mutex_exit(&fcsm->sm_mutex);
3377
3378 ASSERT(cmd->cmd_transport != NULL);
3379 status = cmd->cmd_transport(fcsm->sm_port_info.port_handle, pkt);
3380 if (status != FC_SUCCESS) {
3381 switch (status) {
3382 case FC_LOGINREQ:
3383 /*
3384 * No need to retry. Return the cause of failure.
3385 * Also update the pkt_state/pkt_reason. Caller of
3386 * this function can decide, whether to call
3387 * 'pkt->pkt_comp' or use the 'status' code returned
3388 * by this function.
3389 */
3390 pkt->pkt_state = FC_PKT_LOCAL_RJT;
3391 pkt->pkt_reason = FC_REASON_LOGIN_REQUIRED;
3392 break;
3393
3394 case FC_DEVICE_BUSY_NEW_RSCN:
3395 /*
3396 * There was a newer RSCN than what fcsm knows about.
3397 * So, just retry again
3398 */
3399 cmd->cmd_retry_count = 0;
3400 /*FALLTHROUGH*/
3401 case FC_OFFLINE:
3402 case FC_STATEC_BUSY:
3403 /*
3404 * TODO: set flag, so that command is retried after
3405 * port is back online.
3406 * FALL Through for now.
3407 */
3408
3409 case FC_TRAN_BUSY:
3410 case FC_NOMEM:
3411 case FC_DEVICE_BUSY:
3412 cmd->cmd_retry_interval = fcsm_retry_interval;
3413 if (fcsm_retry_cmd(cmd) != 0) {
3414 FCSM_DEBUG(SMDL_TRACE,
3415 (CE_WARN, SM_LOG, fcsm, NULL,
3416 "issue_cmd: max retries (%d) reached",
3417 cmd->cmd_retry_count));
3418
3419 /*
3420 * status variable is not changed here.
3421 * Return the cause of the original
3422 * cmd_transport failure.
3423 * Update the pkt_state/pkt_reason. Caller
3424 * of this function can decide whether to
3425 * call 'pkt->pkt_comp' or use the 'status'
3426 * code returned by this function.
3427 */
3428 pkt->pkt_state = FC_PKT_TRAN_BSY;
3429 pkt->pkt_reason = 0;
3430 } else {
3431 FCSM_DEBUG(SMDL_TRACE,
3432 (CE_WARN, SM_LOG, fcsm, NULL,
3433 "issue_cmd: retry (%d) on fc status (0x%x)",
3434 cmd->cmd_retry_count, status));
3435
3436 status = FC_SUCCESS;
3437 }
3438 break;
3439
3440 default:
3441 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3442 "issue_cmd: failure status 0x%x", status));
3443
3444 pkt->pkt_state = FC_PKT_TRAN_ERROR;
3445 pkt->pkt_reason = 0;
3446 break;
3447
3448
3449 }
3450 }
3451
3452 return (status);
3453 }
3454
3455
3456 static int
fcsm_retry_cmd(fcsm_cmd_t * cmd)3457 fcsm_retry_cmd(fcsm_cmd_t *cmd)
3458 {
3459 if (cmd->cmd_retry_count < cmd->cmd_max_retries) {
3460 cmd->cmd_retry_count++;
3461 fcsm_enque_cmd(cmd->cmd_fcsm, cmd);
3462 return (0);
3463 }
3464
3465 return (1);
3466 }
3467
3468 static void
fcsm_enque_cmd(fcsm_t * fcsm,fcsm_cmd_t * cmd)3469 fcsm_enque_cmd(fcsm_t *fcsm, fcsm_cmd_t *cmd)
3470 {
3471 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3472
3473 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "enque_cmd"));
3474
3475 cmd->cmd_next = NULL;
3476 mutex_enter(&fcsm->sm_mutex);
3477 if (fcsm->sm_retry_tail) {
3478 ASSERT(fcsm->sm_retry_head != NULL);
3479 fcsm->sm_retry_tail->cmd_next = cmd;
3480 fcsm->sm_retry_tail = cmd;
3481 } else {
3482 ASSERT(fcsm->sm_retry_tail == NULL);
3483 fcsm->sm_retry_head = fcsm->sm_retry_tail = cmd;
3484
3485 /* Schedule retry thread, if not already running */
3486 if (fcsm->sm_retry_tid == NULL) {
3487 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3488 "enque_cmd: schedule retry thread"));
3489 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3490 (caddr_t)fcsm, fcsm_retry_ticks);
3491 }
3492 }
3493 mutex_exit(&fcsm->sm_mutex);
3494 }
3495
3496
3497 static fcsm_cmd_t *
fcsm_deque_cmd(fcsm_t * fcsm)3498 fcsm_deque_cmd(fcsm_t *fcsm)
3499 {
3500 fcsm_cmd_t *cmd;
3501
3502 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3503
3504 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "deque_cmd"));
3505
3506 mutex_enter(&fcsm->sm_mutex);
3507 if (fcsm->sm_retry_head == NULL) {
3508 ASSERT(fcsm->sm_retry_tail == NULL);
3509 cmd = NULL;
3510 } else {
3511 cmd = fcsm->sm_retry_head;
3512 fcsm->sm_retry_head = cmd->cmd_next;
3513 if (fcsm->sm_retry_head == NULL) {
3514 fcsm->sm_retry_tail = NULL;
3515 }
3516 cmd->cmd_next = NULL;
3517 }
3518 mutex_exit(&fcsm->sm_mutex);
3519
3520 return (cmd);
3521 }
3522
3523 static void
fcsm_retry_timeout(void * handle)3524 fcsm_retry_timeout(void *handle)
3525 {
3526 fcsm_t *fcsm;
3527 fcsm_cmd_t *curr_tail;
3528 fcsm_cmd_t *cmd;
3529 int done = 0;
3530 int linkdown;
3531
3532 fcsm = (fcsm_t *)handle;
3533
3534 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "retry_timeout"));
3535
3536 /*
3537 * If retry cmd queue is suspended, then go away.
3538 * This retry thread will be restarted, when cmd queue resumes.
3539 */
3540 mutex_enter(&fcsm->sm_mutex);
3541 if (fcsm->sm_flags & FCSM_CMD_RETRY_Q_SUSPENDED) {
3542 /*
3543 * Clear the retry_tid, to indicate that this routine is not
3544 * currently being rescheduled.
3545 */
3546 fcsm->sm_retry_tid = (timeout_id_t)NULL;
3547 mutex_exit(&fcsm->sm_mutex);
3548 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3549 "retry_timeout: end. No processing. "
3550 "Queue is currently suspended for this instance"));
3551 return;
3552 }
3553
3554 linkdown = (fcsm->sm_flags & FCSM_LINK_DOWN) ? 1 : 0;
3555
3556 /*
3557 * Save the curr_tail, so that we only process the commands
3558 * which are in the queue at this time.
3559 */
3560 curr_tail = fcsm->sm_retry_tail;
3561 mutex_exit(&fcsm->sm_mutex);
3562
3563 /*
3564 * Check for done flag before dequeing the command.
3565 * Dequeing before checking the done flag will cause a command
3566 * to be lost.
3567 */
3568 while ((!done) && ((cmd = fcsm_deque_cmd(fcsm)) != NULL)) {
3569
3570 if (cmd == curr_tail) {
3571 done = 1;
3572 }
3573
3574 cmd->cmd_retry_interval -= fcsm_retry_ticker;
3575
3576 if (linkdown) {
3577 fc_packet_t *pkt;
3578
3579 /*
3580 * No need to retry the command. The link has
3581 * suffered an offline timeout.
3582 */
3583 pkt = cmd->cmd_fp_pkt;
3584 pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3585 pkt->pkt_reason = FC_REASON_OFFLINE;
3586 pkt->pkt_comp(pkt);
3587 continue;
3588 }
3589
3590 if (cmd->cmd_retry_interval <= 0) {
3591 /* Retry the command */
3592 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3593 "retry_timeout: issue cmd 0x%p", (void *)cmd));
3594 if (fcsm_issue_cmd(cmd) != FC_SUCCESS) {
3595 cmd->cmd_fp_pkt->pkt_comp(cmd->cmd_fp_pkt);
3596 }
3597 } else {
3598 /*
3599 * Put the command back on the queue. Retry time
3600 * has not yet reached.
3601 */
3602 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3603 "retry_timeout: queue cmd 0x%p", (void *)cmd));
3604 fcsm_enque_cmd(fcsm, cmd);
3605 }
3606 }
3607
3608 mutex_enter(&fcsm->sm_mutex);
3609 if (fcsm->sm_retry_head) {
3610 /* Activate timer */
3611 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3612 (caddr_t)fcsm, fcsm_retry_ticks);
3613 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3614 "retry_timeout: retry thread rescheduled"));
3615 } else {
3616 /*
3617 * Reset the tid variable. The first thread which queues the
3618 * command, will restart the timer.
3619 */
3620 fcsm->sm_retry_tid = (timeout_id_t)NULL;
3621 }
3622 mutex_exit(&fcsm->sm_mutex);
3623 }
3624