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