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