Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/impl/fp.c
+++ new/usr/src/uts/common/io/fibre-channel/impl/fp.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 *
24 24 * NOT a DDI compliant Sun Fibre Channel port driver(fp)
25 25 *
26 26 */
27 27
28 28 #include <sys/types.h>
29 29 #include <sys/varargs.h>
30 30 #include <sys/param.h>
31 31 #include <sys/errno.h>
32 32 #include <sys/uio.h>
33 33 #include <sys/buf.h>
34 34 #include <sys/modctl.h>
35 35 #include <sys/open.h>
36 36 #include <sys/file.h>
37 37 #include <sys/kmem.h>
38 38 #include <sys/poll.h>
39 39 #include <sys/conf.h>
40 40 #include <sys/thread.h>
41 41 #include <sys/var.h>
42 42 #include <sys/cmn_err.h>
43 43 #include <sys/stat.h>
44 44 #include <sys/ddi.h>
45 45 #include <sys/sunddi.h>
46 46 #include <sys/promif.h>
47 47 #include <sys/nvpair.h>
48 48 #include <sys/byteorder.h>
49 49 #include <sys/scsi/scsi.h>
50 50 #include <sys/fibre-channel/fc.h>
51 51 #include <sys/fibre-channel/impl/fc_ulpif.h>
52 52 #include <sys/fibre-channel/impl/fc_fcaif.h>
53 53 #include <sys/fibre-channel/impl/fctl_private.h>
54 54 #include <sys/fibre-channel/impl/fc_portif.h>
55 55 #include <sys/fibre-channel/impl/fp.h>
56 56
57 57 /* These are defined in fctl.c! */
58 58 extern int did_table_size;
59 59 extern int pwwn_table_size;
60 60
61 61 static struct cb_ops fp_cb_ops = {
62 62 fp_open, /* open */
63 63 fp_close, /* close */
64 64 nodev, /* strategy */
65 65 nodev, /* print */
66 66 nodev, /* dump */
67 67 nodev, /* read */
68 68 nodev, /* write */
69 69 fp_ioctl, /* ioctl */
70 70 nodev, /* devmap */
71 71 nodev, /* mmap */
72 72 nodev, /* segmap */
73 73 nochpoll, /* chpoll */
74 74 ddi_prop_op, /* cb_prop_op */
75 75 0, /* streamtab */
76 76 D_NEW | D_MP | D_HOTPLUG, /* cb_flag */
77 77 CB_REV, /* rev */
78 78 nodev, /* aread */
79 79 nodev /* awrite */
80 80 };
81 81
82 82 static struct dev_ops fp_ops = {
83 83 DEVO_REV, /* build revision */
84 84 0, /* reference count */
85 85 fp_getinfo, /* getinfo */
86 86 nulldev, /* identify - Obsoleted */
87 87 nulldev, /* probe */
88 88 fp_attach, /* attach */
89 89 fp_detach, /* detach */
90 90 nodev, /* reset */
91 91 &fp_cb_ops, /* cb_ops */
92 92 NULL, /* bus_ops */
93 93 fp_power, /* power */
94 94 ddi_quiesce_not_needed /* quiesce */
95 95 };
96 96
97 97 #define FP_VERSION "20091123-1.101"
98 98 #define FP_NAME_VERSION "SunFC Port v" FP_VERSION
99 99
100 100 char *fp_version = FP_NAME_VERSION;
101 101
102 102 static struct modldrv modldrv = {
103 103 &mod_driverops, /* Type of Module */
104 104 FP_NAME_VERSION, /* Name/Version of fp */
105 105 &fp_ops /* driver ops */
106 106 };
107 107
108 108 static struct modlinkage modlinkage = {
109 109 MODREV_1, /* Rev of the loadable modules system */
110 110 &modldrv, /* NULL terminated list of */
111 111 NULL /* Linkage structures */
112 112 };
113 113
114 114
115 115
116 116 static uint16_t ns_reg_cmds[] = {
117 117 NS_RPN_ID,
118 118 NS_RNN_ID,
119 119 NS_RCS_ID,
120 120 NS_RFT_ID,
121 121 NS_RPT_ID,
122 122 NS_RSPN_ID,
123 123 NS_RSNN_NN
124 124 };
125 125
126 126 struct fp_xlat {
127 127 uchar_t xlat_state;
128 128 int xlat_rval;
129 129 } fp_xlat [] = {
130 130 { FC_PKT_SUCCESS, FC_SUCCESS },
131 131 { FC_PKT_REMOTE_STOP, FC_FAILURE },
132 132 { FC_PKT_LOCAL_RJT, FC_FAILURE },
133 133 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT },
134 134 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT },
135 135 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY },
136 136 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY },
137 137 { FC_PKT_NPORT_BSY, FC_PBUSY },
138 138 { FC_PKT_FABRIC_BSY, FC_FBUSY },
139 139 { FC_PKT_LS_RJT, FC_FAILURE },
140 140 { FC_PKT_BA_RJT, FC_FAILURE },
141 141 { FC_PKT_TIMEOUT, FC_FAILURE },
142 142 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR },
143 143 { FC_PKT_FAILURE, FC_FAILURE },
144 144 { FC_PKT_PORT_OFFLINE, FC_OFFLINE }
145 145 };
146 146
147 147 static uchar_t fp_valid_alpas[] = {
148 148 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
149 149 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
150 150 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
151 151 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
152 152 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
153 153 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
154 154 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
155 155 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
156 156 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
157 157 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
158 158 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
159 159 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
160 160 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
161 161 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
162 162 };
163 163
164 164 static struct fp_perms {
165 165 uint16_t fp_ioctl_cmd;
166 166 uchar_t fp_open_flag;
167 167 } fp_perm_list [] = {
168 168 { FCIO_GET_NUM_DEVS, FP_OPEN },
169 169 { FCIO_GET_DEV_LIST, FP_OPEN },
170 170 { FCIO_GET_SYM_PNAME, FP_OPEN },
171 171 { FCIO_GET_SYM_NNAME, FP_OPEN },
172 172 { FCIO_SET_SYM_PNAME, FP_EXCL },
173 173 { FCIO_SET_SYM_NNAME, FP_EXCL },
174 174 { FCIO_GET_LOGI_PARAMS, FP_OPEN },
175 175 { FCIO_DEV_LOGIN, FP_EXCL },
176 176 { FCIO_DEV_LOGOUT, FP_EXCL },
177 177 { FCIO_GET_STATE, FP_OPEN },
178 178 { FCIO_DEV_REMOVE, FP_EXCL },
179 179 { FCIO_GET_FCODE_REV, FP_OPEN },
180 180 { FCIO_GET_FW_REV, FP_OPEN },
181 181 { FCIO_GET_DUMP_SIZE, FP_OPEN },
182 182 { FCIO_FORCE_DUMP, FP_EXCL },
183 183 { FCIO_GET_DUMP, FP_OPEN },
184 184 { FCIO_GET_TOPOLOGY, FP_OPEN },
185 185 { FCIO_RESET_LINK, FP_EXCL },
186 186 { FCIO_RESET_HARD, FP_EXCL },
187 187 { FCIO_RESET_HARD_CORE, FP_EXCL },
188 188 { FCIO_DIAG, FP_OPEN },
189 189 { FCIO_NS, FP_EXCL },
190 190 { FCIO_DOWNLOAD_FW, FP_EXCL },
191 191 { FCIO_DOWNLOAD_FCODE, FP_EXCL },
192 192 { FCIO_LINK_STATUS, FP_OPEN },
193 193 { FCIO_GET_HOST_PARAMS, FP_OPEN },
194 194 { FCIO_GET_NODE_ID, FP_OPEN },
195 195 { FCIO_SET_NODE_ID, FP_EXCL },
196 196 { FCIO_SEND_NODE_ID, FP_OPEN },
197 197 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN },
198 198 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN },
199 199 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN },
200 200 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN },
201 201 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN },
202 202 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN },
203 203 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
204 204 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
205 205 { FCIO_DELETE_NPIV_PORT, FP_OPEN },
206 206 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
207 207 { FCIO_CREATE_NPIV_PORT, FP_OPEN },
208 208 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
209 209 };
210 210
211 211 static char *fp_pm_comps[] = {
212 212 "NAME=FC Port",
213 213 "0=Port Down",
214 214 "1=Port Up"
215 215 };
216 216
217 217
218 218 #ifdef _LITTLE_ENDIAN
219 219 #define MAKE_BE_32(x) { \
220 220 uint32_t *ptr1, i; \
221 221 ptr1 = (uint32_t *)(x); \
222 222 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
223 223 *ptr1 = BE_32(*ptr1); \
224 224 ptr1++; \
225 225 } \
226 226 }
227 227 #else
228 228 #define MAKE_BE_32(x)
229 229 #endif
230 230
231 231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
232 232 static uint32_t fp_options = 0;
233 233
234 234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
235 235 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */
236 236 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */
237 237 unsigned int fp_offline_ticker; /* seconds */
238 238
239 239 /*
240 240 * Driver global variable to anchor the list of soft state structs for
241 241 * all fp driver instances. Used with the Solaris DDI soft state functions.
242 242 */
243 243 static void *fp_driver_softstate;
244 244
245 245 static clock_t fp_retry_ticks;
246 246 static clock_t fp_offline_ticks;
247 247
248 248 static int fp_retry_ticker;
249 249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
250 250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
251 251
252 252 static int fp_log_size = FP_LOG_SIZE;
253 253 static int fp_trace = FP_TRACE_DEFAULT;
254 254 static fc_trace_logq_t *fp_logq = NULL;
255 255
256 256 int fp_get_adapter_paths(char *pathList, int count);
257 257 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
258 258 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
259 259 la_wwn_t tgt_pwwn, uint32_t port_id);
260 260 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
261 261 static void fp_init_symbolic_names(fc_local_port_t *port);
262 262
263 263
264 264 /*
265 265 * Perform global initialization
266 266 */
267 267 int
268 268 _init(void)
269 269 {
270 270 int ret;
271 271
272 272 if ((ret = ddi_soft_state_init(&fp_driver_softstate,
273 273 sizeof (struct fc_local_port), 8)) != 0) {
274 274 return (ret);
275 275 }
276 276
277 277 if ((ret = scsi_hba_init(&modlinkage)) != 0) {
278 278 ddi_soft_state_fini(&fp_driver_softstate);
279 279 return (ret);
280 280 }
281 281
282 282 fp_logq = fc_trace_alloc_logq(fp_log_size);
283 283
284 284 if ((ret = mod_install(&modlinkage)) != 0) {
285 285 fc_trace_free_logq(fp_logq);
286 286 ddi_soft_state_fini(&fp_driver_softstate);
287 287 scsi_hba_fini(&modlinkage);
288 288 }
289 289
290 290 return (ret);
291 291 }
292 292
293 293
294 294 /*
295 295 * Prepare for driver unload
296 296 */
297 297 int
298 298 _fini(void)
299 299 {
300 300 int ret;
301 301
302 302 if ((ret = mod_remove(&modlinkage)) == 0) {
303 303 fc_trace_free_logq(fp_logq);
304 304 ddi_soft_state_fini(&fp_driver_softstate);
305 305 scsi_hba_fini(&modlinkage);
306 306 }
307 307
308 308 return (ret);
309 309 }
310 310
311 311
312 312 /*
313 313 * Request mod_info() to handle all cases
314 314 */
315 315 int
316 316 _info(struct modinfo *modinfo)
317 317 {
318 318 return (mod_info(&modlinkage, modinfo));
319 319 }
320 320
321 321
322 322 /*
323 323 * fp_attach:
324 324 *
325 325 * The respective cmd handlers take care of performing
326 326 * ULP related invocations
327 327 */
328 328 static int
329 329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
330 330 {
331 331 int rval;
332 332
333 333 /*
334 334 * We check the value of fp_offline_ticker at this
335 335 * point. The variable is global for the driver and
336 336 * not specific to an instance.
337 337 *
338 338 * If there is no user-defined value found in /etc/system
339 339 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
340 340 * The minimum setting for this offline timeout according
341 341 * to the FC-FS2 standard (Fibre Channel Framing and
342 342 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
343 343 *
344 344 * We do not recommend setting the value to less than 10
345 345 * seconds (RA_TOV) or more than 90 seconds. If this
346 346 * variable is greater than 90 seconds then drivers above
347 347 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
348 348 */
349 349
350 350 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
351 351 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
352 352 FP_OFFLINE_TICKER);
353 353
354 354 if ((fp_offline_ticker < 10) ||
355 355 (fp_offline_ticker > 90)) {
356 356 cmn_err(CE_WARN, "Setting fp_offline_ticker to "
357 357 "%d second(s). This is outside the "
358 358 "recommended range of 10..90 seconds",
359 359 fp_offline_ticker);
360 360 }
361 361
362 362 /*
363 363 * Tick every second when there are commands to retry.
364 364 * It should tick at the least granular value of pkt_timeout
365 365 * (which is one second)
366 366 */
367 367 fp_retry_ticker = 1;
368 368
369 369 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
370 370 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
371 371
372 372 switch (cmd) {
373 373 case DDI_ATTACH:
374 374 rval = fp_attach_handler(dip);
375 375 break;
376 376
377 377 case DDI_RESUME:
378 378 rval = fp_resume_handler(dip);
379 379 break;
380 380
381 381 default:
382 382 rval = DDI_FAILURE;
383 383 break;
384 384 }
385 385 return (rval);
386 386 }
387 387
388 388
389 389 /*
390 390 * fp_detach:
391 391 *
392 392 * If a ULP fails to handle cmd request converse of
393 393 * cmd is invoked for ULPs that previously succeeded
394 394 * cmd request.
395 395 */
396 396 static int
397 397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
398 398 {
399 399 int rval = DDI_FAILURE;
400 400 fc_local_port_t *port;
401 401 fc_attach_cmd_t converse;
402 402 uint8_t cnt;
403 403
404 404 if ((port = ddi_get_soft_state(fp_driver_softstate,
405 405 ddi_get_instance(dip))) == NULL) {
406 406 return (DDI_FAILURE);
407 407 }
408 408
409 409 mutex_enter(&port->fp_mutex);
410 410
411 411 if (port->fp_ulp_attach) {
412 412 mutex_exit(&port->fp_mutex);
413 413 return (DDI_FAILURE);
414 414 }
415 415
416 416 switch (cmd) {
417 417 case DDI_DETACH:
418 418 if (port->fp_task != FP_TASK_IDLE) {
419 419 mutex_exit(&port->fp_mutex);
420 420 return (DDI_FAILURE);
421 421 }
422 422
423 423 /* Let's attempt to quit the job handler gracefully */
424 424 port->fp_soft_state |= FP_DETACH_INPROGRESS;
425 425
426 426 mutex_exit(&port->fp_mutex);
427 427 converse = FC_CMD_ATTACH;
428 428 if (fctl_detach_ulps(port, FC_CMD_DETACH,
429 429 &modlinkage) != FC_SUCCESS) {
430 430 mutex_enter(&port->fp_mutex);
431 431 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
432 432 mutex_exit(&port->fp_mutex);
433 433 rval = DDI_FAILURE;
434 434 break;
435 435 }
436 436
437 437 mutex_enter(&port->fp_mutex);
438 438 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
439 439 cnt++) {
440 440 mutex_exit(&port->fp_mutex);
441 441 delay(drv_usectohz(1000000));
442 442 mutex_enter(&port->fp_mutex);
443 443 }
444 444
445 445 if (port->fp_job_head) {
446 446 mutex_exit(&port->fp_mutex);
447 447 rval = DDI_FAILURE;
448 448 break;
449 449 }
450 450 mutex_exit(&port->fp_mutex);
451 451
452 452 rval = fp_detach_handler(port);
453 453 break;
454 454
455 455 case DDI_SUSPEND:
456 456 mutex_exit(&port->fp_mutex);
457 457 converse = FC_CMD_RESUME;
458 458 if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
459 459 &modlinkage) != FC_SUCCESS) {
460 460 rval = DDI_FAILURE;
461 461 break;
462 462 }
463 463 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
464 464 (void) callb_generic_cpr(&port->fp_cpr_info,
465 465 CB_CODE_CPR_RESUME);
466 466 }
467 467 break;
468 468
469 469 default:
470 470 mutex_exit(&port->fp_mutex);
471 471 break;
472 472 }
473 473
474 474 /*
475 475 * Use softint to perform reattach. Mark fp_ulp_attach so we
476 476 * don't attempt to do this repeatedly on behalf of some persistent
477 477 * caller.
478 478 */
479 479 if (rval != DDI_SUCCESS) {
480 480 mutex_enter(&port->fp_mutex);
481 481 port->fp_ulp_attach = 1;
482 482
483 483 /*
484 484 * If the port is in the low power mode then there is
485 485 * possibility that fca too could be in low power mode.
486 486 * Try to raise the power before calling attach ulps.
487 487 */
488 488
489 489 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
490 490 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
491 491 mutex_exit(&port->fp_mutex);
492 492 (void) pm_raise_power(port->fp_port_dip,
493 493 FP_PM_COMPONENT, FP_PM_PORT_UP);
494 494 } else {
495 495 mutex_exit(&port->fp_mutex);
496 496 }
497 497
498 498
499 499 fp_attach_ulps(port, converse);
500 500
501 501 mutex_enter(&port->fp_mutex);
502 502 while (port->fp_ulp_attach) {
503 503 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
504 504 }
505 505
506 506 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
507 507
508 508 /*
509 509 * Mark state as detach failed so asynchronous ULP attach
510 510 * events (downstream, not the ones we're initiating with
511 511 * the call to fp_attach_ulps) are not honored. We're
512 512 * really still in pending detach.
513 513 */
514 514 port->fp_soft_state |= FP_DETACH_FAILED;
515 515
516 516 mutex_exit(&port->fp_mutex);
517 517 }
518 518
519 519 return (rval);
520 520 }
521 521
522 522
523 523 /*
524 524 * fp_getinfo:
525 525 * Given the device number, return either the
526 526 * dev_info_t pointer or the instance number.
527 527 */
528 528
529 529 /* ARGSUSED */
530 530 static int
531 531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
532 532 {
533 533 int rval;
534 534 minor_t instance;
535 535 fc_local_port_t *port;
536 536
537 537 rval = DDI_SUCCESS;
538 538 instance = getminor((dev_t)arg);
539 539
540 540 switch (cmd) {
541 541 case DDI_INFO_DEVT2DEVINFO:
542 542 if ((port = ddi_get_soft_state(fp_driver_softstate,
543 543 instance)) == NULL) {
544 544 rval = DDI_FAILURE;
545 545 break;
546 546 }
547 547 *result = (void *)port->fp_port_dip;
548 548 break;
549 549
550 550 case DDI_INFO_DEVT2INSTANCE:
551 551 *result = (void *)(uintptr_t)instance;
552 552 break;
553 553
554 554 default:
555 555 rval = DDI_FAILURE;
556 556 break;
557 557 }
558 558
559 559 return (rval);
560 560 }
561 561
562 562
563 563 /*
564 564 * Entry point for power up and power down request from kernel
565 565 */
566 566 static int
567 567 fp_power(dev_info_t *dip, int comp, int level)
568 568 {
569 569 int rval = DDI_FAILURE;
570 570 fc_local_port_t *port;
571 571
572 572 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
573 573 if (port == NULL || comp != FP_PM_COMPONENT) {
574 574 return (rval);
575 575 }
576 576
577 577 switch (level) {
578 578 case FP_PM_PORT_UP:
579 579 rval = DDI_SUCCESS;
580 580
581 581 /*
582 582 * If the port is DDI_SUSPENDed, let the DDI_RESUME
583 583 * code complete the rediscovery.
584 584 */
585 585 mutex_enter(&port->fp_mutex);
586 586 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
587 587 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
588 588 port->fp_pm_level = FP_PM_PORT_UP;
589 589 mutex_exit(&port->fp_mutex);
590 590 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
591 591 break;
592 592 }
593 593
594 594 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
595 595 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
596 596
597 597 port->fp_pm_level = FP_PM_PORT_UP;
598 598 rval = fp_power_up(port);
599 599 if (rval != DDI_SUCCESS) {
600 600 port->fp_pm_level = FP_PM_PORT_DOWN;
601 601 }
602 602 } else {
603 603 port->fp_pm_level = FP_PM_PORT_UP;
604 604 }
605 605 mutex_exit(&port->fp_mutex);
606 606 break;
607 607
608 608 case FP_PM_PORT_DOWN:
609 609 mutex_enter(&port->fp_mutex);
610 610
611 611 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
612 612 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
613 613 /*
614 614 * PM framework goofed up. We have don't
615 615 * have any PM components. Let's never go down.
616 616 */
617 617 mutex_exit(&port->fp_mutex);
618 618 break;
619 619
620 620 }
621 621
622 622 if (port->fp_ulp_attach) {
623 623 /* We shouldn't let the power go down */
624 624 mutex_exit(&port->fp_mutex);
625 625 break;
626 626 }
627 627
628 628 /*
629 629 * Not a whole lot to do if we are detaching
630 630 */
631 631 if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
632 632 port->fp_pm_level = FP_PM_PORT_DOWN;
633 633 mutex_exit(&port->fp_mutex);
634 634 rval = DDI_SUCCESS;
635 635 break;
636 636 }
637 637
638 638 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
639 639 port->fp_pm_level = FP_PM_PORT_DOWN;
640 640
641 641 rval = fp_power_down(port);
642 642 if (rval != DDI_SUCCESS) {
643 643 port->fp_pm_level = FP_PM_PORT_UP;
644 644 ASSERT(!(port->fp_soft_state &
645 645 FP_SOFT_POWER_DOWN));
646 646 } else {
647 647 ASSERT(port->fp_soft_state &
648 648 FP_SOFT_POWER_DOWN);
649 649 }
650 650 }
651 651 mutex_exit(&port->fp_mutex);
652 652 break;
653 653
654 654 default:
655 655 break;
656 656 }
657 657
658 658 return (rval);
659 659 }
660 660
661 661
662 662 /*
663 663 * Open FC port devctl node
664 664 */
665 665 static int
666 666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
667 667 {
668 668 int instance;
669 669 fc_local_port_t *port;
670 670
671 671 if (otype != OTYP_CHR) {
672 672 return (EINVAL);
673 673 }
674 674
675 675 /*
676 676 * This is not a toy to play with. Allow only powerful
677 677 * users (hopefully knowledgeable) to access the port
678 678 * (A hacker potentially could download a sick binary
679 679 * file into FCA)
680 680 */
681 681 if (drv_priv(credp)) {
682 682 return (EPERM);
683 683 }
684 684
685 685 instance = (int)getminor(*devp);
686 686
687 687 port = ddi_get_soft_state(fp_driver_softstate, instance);
688 688 if (port == NULL) {
689 689 return (ENXIO);
690 690 }
691 691
692 692 mutex_enter(&port->fp_mutex);
693 693 if (port->fp_flag & FP_EXCL) {
694 694 /*
695 695 * It is already open for exclusive access.
696 696 * So shut the door on this caller.
697 697 */
698 698 mutex_exit(&port->fp_mutex);
699 699 return (EBUSY);
700 700 }
701 701
702 702 if (flag & FEXCL) {
703 703 if (port->fp_flag & FP_OPEN) {
704 704 /*
705 705 * Exclusive operation not possible
706 706 * as it is already opened
707 707 */
708 708 mutex_exit(&port->fp_mutex);
709 709 return (EBUSY);
710 710 }
711 711 port->fp_flag |= FP_EXCL;
712 712 }
713 713 port->fp_flag |= FP_OPEN;
714 714 mutex_exit(&port->fp_mutex);
715 715
716 716 return (0);
717 717 }
718 718
719 719
720 720 /*
721 721 * The driver close entry point is called on the last close()
722 722 * of a device. So it is perfectly alright to just clobber the
723 723 * open flag and reset it to idle (instead of having to reset
724 724 * each flag bits). For any confusion, check out close(9E).
725 725 */
726 726
727 727 /* ARGSUSED */
728 728 static int
729 729 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
730 730 {
731 731 int instance;
732 732 fc_local_port_t *port;
733 733
734 734 if (otype != OTYP_CHR) {
735 735 return (EINVAL);
736 736 }
737 737
738 738 instance = (int)getminor(dev);
739 739
740 740 port = ddi_get_soft_state(fp_driver_softstate, instance);
741 741 if (port == NULL) {
742 742 return (ENXIO);
743 743 }
744 744
745 745 mutex_enter(&port->fp_mutex);
746 746 if ((port->fp_flag & FP_OPEN) == 0) {
747 747 mutex_exit(&port->fp_mutex);
748 748 return (ENODEV);
749 749 }
750 750 port->fp_flag = FP_IDLE;
751 751 mutex_exit(&port->fp_mutex);
752 752
753 753 return (0);
754 754 }
755 755
756 756 /*
757 757 * Handle IOCTL requests
758 758 */
759 759
760 760 /* ARGSUSED */
761 761 static int
762 762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
763 763 {
764 764 int instance;
765 765 int ret = 0;
766 766 fcio_t fcio;
767 767 fc_local_port_t *port;
768 768
769 769 instance = (int)getminor(dev);
770 770
771 771 port = ddi_get_soft_state(fp_driver_softstate, instance);
772 772 if (port == NULL) {
773 773 return (ENXIO);
774 774 }
775 775
776 776 mutex_enter(&port->fp_mutex);
777 777 if ((port->fp_flag & FP_OPEN) == 0) {
778 778 mutex_exit(&port->fp_mutex);
779 779 return (ENXIO);
780 780 }
781 781
782 782 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
783 783 mutex_exit(&port->fp_mutex);
784 784 return (ENXIO);
785 785 }
786 786
787 787 mutex_exit(&port->fp_mutex);
788 788
789 789 /* this will raise power if necessary */
790 790 ret = fctl_busy_port(port);
791 791 if (ret != 0) {
792 792 return (ret);
793 793 }
794 794
795 795 ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
796 796
797 797
798 798 switch (cmd) {
799 799 case FCIO_CMD: {
800 800 #ifdef _MULTI_DATAMODEL
801 801 switch (ddi_model_convert_from(mode & FMODELS)) {
802 802 case DDI_MODEL_ILP32: {
803 803 struct fcio32 fcio32;
804 804
805 805 if (ddi_copyin((void *)data, (void *)&fcio32,
806 806 sizeof (struct fcio32), mode)) {
807 807 ret = EFAULT;
808 808 break;
809 809 }
810 810 fcio.fcio_xfer = fcio32.fcio_xfer;
811 811 fcio.fcio_cmd = fcio32.fcio_cmd;
812 812 fcio.fcio_flags = fcio32.fcio_flags;
813 813 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
814 814 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
815 815 fcio.fcio_ibuf =
816 816 (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
817 817 fcio.fcio_olen = (size_t)fcio32.fcio_olen;
818 818 fcio.fcio_obuf =
819 819 (caddr_t)(uintptr_t)fcio32.fcio_obuf;
820 820 fcio.fcio_alen = (size_t)fcio32.fcio_alen;
821 821 fcio.fcio_abuf =
822 822 (caddr_t)(uintptr_t)fcio32.fcio_abuf;
823 823 fcio.fcio_errno = fcio32.fcio_errno;
824 824 break;
825 825 }
826 826
827 827 case DDI_MODEL_NONE:
828 828 if (ddi_copyin((void *)data, (void *)&fcio,
829 829 sizeof (fcio_t), mode)) {
830 830 ret = EFAULT;
831 831 }
832 832 break;
833 833 }
834 834 #else /* _MULTI_DATAMODEL */
835 835 if (ddi_copyin((void *)data, (void *)&fcio,
836 836 sizeof (fcio_t), mode)) {
837 837 ret = EFAULT;
838 838 break;
839 839 }
840 840 #endif /* _MULTI_DATAMODEL */
841 841 if (!ret) {
842 842 ret = fp_fciocmd(port, data, mode, &fcio);
843 843 }
844 844 break;
845 845 }
846 846
847 847 default:
848 848 ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
849 849 mode, credp, rval);
850 850 }
851 851
852 852 fctl_idle_port(port);
853 853
854 854 return (ret);
855 855 }
856 856
857 857
858 858 /*
859 859 * Init Symbolic Port Name and Node Name
860 860 * LV will try to get symbolic names from FCA driver
861 861 * and register these to name server,
862 862 * if LV fails to get these,
863 863 * LV will register its default symbolic names to name server.
864 864 * The Default symbolic node name format is :
865 865 * <hostname>:<hba driver name>(instance)
866 866 * The Default symbolic port name format is :
867 867 * <fp path name>
868 868 */
869 869 static void
870 870 fp_init_symbolic_names(fc_local_port_t *port)
871 871 {
872 872 const char *vendorname = ddi_driver_name(port->fp_fca_dip);
873 873 char *sym_name;
874 874 char fcaname[50] = {0};
875 875 int hostnlen, fcanlen;
876 876
877 877 if (port->fp_sym_node_namelen == 0) {
878 878 hostnlen = strlen(utsname.nodename);
879 879 (void) snprintf(fcaname, sizeof (fcaname),
880 880 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
881 881 fcanlen = strlen(fcaname);
882 882
883 883 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
884 884 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
885 885 port->fp_sym_node_namelen = strlen(sym_name);
886 886 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
887 887 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
888 888 }
889 889 (void) strncpy(port->fp_sym_node_name, sym_name,
890 890 port->fp_sym_node_namelen);
891 891 kmem_free(sym_name, hostnlen + fcanlen + 2);
892 892 }
893 893
894 894 if (port->fp_sym_port_namelen == 0) {
895 895 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
896 896
897 897 (void) ddi_pathname(port->fp_port_dip, pathname);
898 898 port->fp_sym_port_namelen = strlen(pathname);
899 899 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
900 900 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
901 901 }
902 902 (void) strncpy(port->fp_sym_port_name, pathname,
903 903 port->fp_sym_port_namelen);
904 904 kmem_free(pathname, MAXPATHLEN);
905 905 }
906 906 }
907 907
908 908
909 909 /*
910 910 * Perform port attach
911 911 */
912 912 static int
913 913 fp_attach_handler(dev_info_t *dip)
914 914 {
915 915 int rval;
916 916 int instance;
917 917 int port_num;
918 918 int port_len;
919 919 char name[30];
920 920 char i_pwwn[17];
921 921 fp_cmd_t *pkt;
922 922 uint32_t ub_count;
923 923 fc_local_port_t *port;
924 924 job_request_t *job;
925 925 fc_local_port_t *phyport = NULL;
926 926 int portpro1;
927 927 char pwwn[17], nwwn[17];
928 928
929 929 instance = ddi_get_instance(dip);
930 930 port_len = sizeof (port_num);
931 931 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
932 932 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
933 933 (caddr_t)&port_num, &port_len);
934 934 if (rval != DDI_SUCCESS) {
935 935 cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
936 936 instance);
937 937 return (DDI_FAILURE);
938 938 }
939 939
940 940 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
941 941 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
942 942 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
943 943 instance);
944 944 return (DDI_FAILURE);
945 945 }
946 946
947 947 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
948 948 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
949 949 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
950 950 " point minor node", instance);
951 951 ddi_remove_minor_node(dip, NULL);
952 952 return (DDI_FAILURE);
953 953 }
954 954
955 955 if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
956 956 != DDI_SUCCESS) {
957 957 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
958 958 instance);
959 959 ddi_remove_minor_node(dip, NULL);
960 960 return (DDI_FAILURE);
961 961 }
962 962 port = ddi_get_soft_state(fp_driver_softstate, instance);
963 963
964 964 (void) sprintf(port->fp_ibuf, "fp(%d)", instance);
965 965
966 966 port->fp_instance = instance;
967 967 port->fp_ulp_attach = 1;
968 968 port->fp_port_num = port_num;
969 969 port->fp_verbose = fp_verbosity;
970 970 port->fp_options = fp_options;
971 971
972 972 port->fp_fca_dip = ddi_get_parent(dip);
973 973 port->fp_port_dip = dip;
974 974 port->fp_fca_tran = (fc_fca_tran_t *)
975 975 ddi_get_driver_private(port->fp_fca_dip);
976 976
977 977 port->fp_task = port->fp_last_task = FP_TASK_IDLE;
978 978
979 979 /*
980 980 * Init the starting value of fp_rscn_count. Note that if
981 981 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
982 982 * actual # of RSCNs will be (fp_rscn_count - 1)
983 983 */
984 984 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
985 985
986 986 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
987 987 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
988 988 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
989 989
990 990 (void) sprintf(name, "fp%d_cache", instance);
991 991
992 992 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
993 993 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
994 994 "phyport-instance", -1)) != -1) {
995 995 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
996 996 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
997 997 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
998 998 port->fp_npiv_type = FC_NPIV_PORT;
999 999 }
1000 1000
1001 1001 /*
1002 1002 * Allocate the pool of fc_packet_t structs to be used with
1003 1003 * this fp instance.
1004 1004 */
1005 1005 port->fp_pkt_cache = kmem_cache_create(name,
1006 1006 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1007 1007 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1008 1008 NULL, 0);
1009 1009 port->fp_out_fpcmds = 0;
1010 1010 if (port->fp_pkt_cache == NULL) {
1011 1011 goto cache_alloc_failed;
1012 1012 }
1013 1013
1014 1014
1015 1015 /*
1016 1016 * Allocate the d_id and pwwn hash tables for all remote ports
1017 1017 * connected to this local port.
1018 1018 */
1019 1019 port->fp_did_table = kmem_zalloc(did_table_size *
1020 1020 sizeof (struct d_id_hash), KM_SLEEP);
1021 1021
1022 1022 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1023 1023 sizeof (struct pwwn_hash), KM_SLEEP);
1024 1024
1025 1025 port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1026 1026 MINCLSYSPRI, 1, 16, 0);
1027 1027
1028 1028 /* Indicate that don't have the pm components yet */
1029 1029 port->fp_soft_state |= FP_SOFT_NO_PMCOMP;
1030 1030
1031 1031 /*
1032 1032 * Bind the callbacks with the FCA driver. This will open the gate
1033 1033 * for asynchronous callbacks, so after this call the fp_mutex
1034 1034 * must be held when updating the fc_local_port_t struct.
1035 1035 *
1036 1036 * This is done _before_ setting up the job thread so we can avoid
1037 1037 * cleaning up after the thread_create() in the error path. This
1038 1038 * also means fp will be operating with fp_els_resp_pkt set to NULL.
1039 1039 */
1040 1040 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1041 1041 goto bind_callbacks_failed;
1042 1042 }
1043 1043
1044 1044 if (phyport) {
1045 1045 mutex_enter(&phyport->fp_mutex);
1046 1046 if (phyport->fp_port_next) {
1047 1047 phyport->fp_port_next->fp_port_prev = port;
1048 1048 port->fp_port_next = phyport->fp_port_next;
1049 1049 phyport->fp_port_next = port;
1050 1050 port->fp_port_prev = phyport;
1051 1051 } else {
1052 1052 phyport->fp_port_next = port;
1053 1053 phyport->fp_port_prev = port;
1054 1054 port->fp_port_next = phyport;
1055 1055 port->fp_port_prev = phyport;
1056 1056 }
1057 1057 mutex_exit(&phyport->fp_mutex);
1058 1058 }
1059 1059
1060 1060 /*
1061 1061 * Init Symbolic Names
1062 1062 */
1063 1063 fp_init_symbolic_names(port);
1064 1064
1065 1065 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1066 1066 KM_SLEEP, NULL);
1067 1067
1068 1068 if (pkt == NULL) {
1069 1069 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1070 1070 instance);
1071 1071 goto alloc_els_packet_failed;
1072 1072 }
1073 1073
1074 1074 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1075 1075 v.v_maxsyspri - 2);
1076 1076
1077 1077 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1078 1078 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1079 1079 i_pwwn) != DDI_PROP_SUCCESS) {
1080 1080 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1081 1081 "fp(%d): Updating 'initiator-port' property"
1082 1082 " on fp dev_info node failed", instance);
1083 1083 }
1084 1084
1085 1085 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1086 1086 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1087 1087 i_pwwn) != DDI_PROP_SUCCESS) {
1088 1088 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1089 1089 "fp(%d): Updating 'initiator-node' property"
1090 1090 " on fp dev_info node failed", instance);
1091 1091 }
1092 1092
1093 1093 mutex_enter(&port->fp_mutex);
1094 1094 port->fp_els_resp_pkt = pkt;
1095 1095 mutex_exit(&port->fp_mutex);
1096 1096
1097 1097 /*
1098 1098 * Determine the count of unsolicited buffers this FCA can support
1099 1099 */
1100 1100 fp_retrieve_caps(port);
1101 1101
1102 1102 /*
1103 1103 * Allocate unsolicited buffer tokens
1104 1104 */
1105 1105 if (port->fp_ub_count) {
1106 1106 ub_count = port->fp_ub_count;
1107 1107 port->fp_ub_tokens = kmem_zalloc(ub_count *
1108 1108 sizeof (*port->fp_ub_tokens), KM_SLEEP);
1109 1109 /*
1110 1110 * Do not fail the attach if unsolicited buffer allocation
1111 1111 * fails; Just try to get along with whatever the FCA can do.
1112 1112 */
1113 1113 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1114 1114 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1115 1115 FC_SUCCESS || ub_count != port->fp_ub_count) {
1116 1116 cmn_err(CE_WARN, "fp(%d): failed to allocate "
1117 1117 " Unsolicited buffers. proceeding with attach...",
1118 1118 instance);
1119 1119 kmem_free(port->fp_ub_tokens,
1120 1120 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1121 1121 port->fp_ub_tokens = NULL;
1122 1122 }
1123 1123 }
1124 1124
1125 1125 fp_load_ulp_modules(dip, port);
1126 1126
1127 1127 /*
1128 1128 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1129 1129 */
1130 1130 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1131 1131 "pm-hardware-state", "needs-suspend-resume",
1132 1132 strlen("needs-suspend-resume") + 1);
1133 1133
1134 1134 /*
1135 1135 * fctl maintains a list of all port handles, so
1136 1136 * help fctl add this one to its list now.
1137 1137 */
1138 1138 mutex_enter(&port->fp_mutex);
1139 1139 fctl_add_port(port);
1140 1140
1141 1141 /*
1142 1142 * If a state change is already in progress, set the bind state t
1143 1143 * OFFLINE as well, so further state change callbacks into ULPs
1144 1144 * will pass the appropriate states
1145 1145 */
1146 1146 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1147 1147 port->fp_statec_busy) {
1148 1148 port->fp_bind_state = FC_STATE_OFFLINE;
1149 1149 mutex_exit(&port->fp_mutex);
1150 1150
1151 1151 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1152 1152 } else {
1153 1153 /*
1154 1154 * Without dropping the mutex, ensure that the port
1155 1155 * startup happens ahead of state change callback
1156 1156 * processing
1157 1157 */
1158 1158 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1159 1159
1160 1160 port->fp_last_task = port->fp_task;
1161 1161 port->fp_task = FP_TASK_PORT_STARTUP;
1162 1162
1163 1163 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1164 1164 fp_startup_done, (opaque_t)port, KM_SLEEP);
1165 1165
1166 1166 port->fp_job_head = port->fp_job_tail = job;
1167 1167
1168 1168 cv_signal(&port->fp_cv);
1169 1169
1170 1170 mutex_exit(&port->fp_mutex);
1171 1171 }
1172 1172
1173 1173 mutex_enter(&port->fp_mutex);
1174 1174 while (port->fp_ulp_attach) {
1175 1175 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1176 1176 }
1177 1177 mutex_exit(&port->fp_mutex);
1178 1178
1179 1179 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1180 1180 "pm-components", fp_pm_comps,
1181 1181 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1182 1182 DDI_PROP_SUCCESS) {
1183 1183 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1184 1184 " components property, PM disabled on this port.");
1185 1185 mutex_enter(&port->fp_mutex);
1186 1186 port->fp_pm_level = FP_PM_PORT_UP;
1187 1187 mutex_exit(&port->fp_mutex);
1188 1188 } else {
1189 1189 if (pm_raise_power(dip, FP_PM_COMPONENT,
1190 1190 FP_PM_PORT_UP) != DDI_SUCCESS) {
1191 1191 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1192 1192 " power level");
1193 1193 mutex_enter(&port->fp_mutex);
1194 1194 port->fp_pm_level = FP_PM_PORT_UP;
1195 1195 mutex_exit(&port->fp_mutex);
1196 1196 }
1197 1197
1198 1198 /*
1199 1199 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1200 1200 * the call to pm_raise_power. The PM framework can't
1201 1201 * handle multiple threads calling into it during attach.
1202 1202 */
1203 1203
1204 1204 mutex_enter(&port->fp_mutex);
1205 1205 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP;
1206 1206 mutex_exit(&port->fp_mutex);
1207 1207 }
1208 1208
1209 1209 ddi_report_dev(dip);
1210 1210
1211 1211 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1212 1212
1213 1213 return (DDI_SUCCESS);
1214 1214
1215 1215 /*
1216 1216 * Unwind any/all preceeding allocations in the event of an error.
1217 1217 */
1218 1218
1219 1219 alloc_els_packet_failed:
1220 1220
1221 1221 if (port->fp_fca_handle != NULL) {
1222 1222 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1223 1223 port->fp_fca_handle = NULL;
1224 1224 }
1225 1225
1226 1226 if (port->fp_ub_tokens != NULL) {
1227 1227 (void) fc_ulp_ubfree(port, port->fp_ub_count,
1228 1228 port->fp_ub_tokens);
1229 1229 kmem_free(port->fp_ub_tokens,
1230 1230 port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1231 1231 port->fp_ub_tokens = NULL;
1232 1232 }
1233 1233
1234 1234 if (port->fp_els_resp_pkt != NULL) {
1235 1235 fp_free_pkt(port->fp_els_resp_pkt);
1236 1236 port->fp_els_resp_pkt = NULL;
1237 1237 }
1238 1238
1239 1239 bind_callbacks_failed:
1240 1240
1241 1241 if (port->fp_taskq != NULL) {
1242 1242 taskq_destroy(port->fp_taskq);
1243 1243 }
1244 1244
1245 1245 if (port->fp_pwwn_table != NULL) {
1246 1246 kmem_free(port->fp_pwwn_table,
1247 1247 pwwn_table_size * sizeof (struct pwwn_hash));
1248 1248 port->fp_pwwn_table = NULL;
1249 1249 }
1250 1250
1251 1251 if (port->fp_did_table != NULL) {
1252 1252 kmem_free(port->fp_did_table,
1253 1253 did_table_size * sizeof (struct d_id_hash));
1254 1254 port->fp_did_table = NULL;
1255 1255 }
1256 1256
1257 1257 if (port->fp_pkt_cache != NULL) {
1258 1258 kmem_cache_destroy(port->fp_pkt_cache);
1259 1259 port->fp_pkt_cache = NULL;
1260 1260 }
1261 1261
1262 1262 cache_alloc_failed:
1263 1263
1264 1264 cv_destroy(&port->fp_attach_cv);
1265 1265 cv_destroy(&port->fp_cv);
1266 1266 mutex_destroy(&port->fp_mutex);
1267 1267 ddi_remove_minor_node(port->fp_port_dip, NULL);
1268 1268 ddi_soft_state_free(fp_driver_softstate, instance);
1269 1269 ddi_prop_remove_all(dip);
1270 1270
1271 1271 return (DDI_FAILURE);
1272 1272 }
1273 1273
1274 1274
1275 1275 /*
1276 1276 * Handle DDI_RESUME request
1277 1277 */
1278 1278 static int
1279 1279 fp_resume_handler(dev_info_t *dip)
1280 1280 {
1281 1281 int rval;
1282 1282 fc_local_port_t *port;
1283 1283
1284 1284 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1285 1285
1286 1286 ASSERT(port != NULL);
1287 1287
1288 1288 #ifdef DEBUG
1289 1289 mutex_enter(&port->fp_mutex);
1290 1290 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1291 1291 mutex_exit(&port->fp_mutex);
1292 1292 #endif
1293 1293
1294 1294 /*
1295 1295 * If the port was power suspended, raise the power level
1296 1296 */
1297 1297 mutex_enter(&port->fp_mutex);
1298 1298 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1299 1299 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1300 1300 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1301 1301
1302 1302 mutex_exit(&port->fp_mutex);
1303 1303 if (pm_raise_power(dip, FP_PM_COMPONENT,
1304 1304 FP_PM_PORT_UP) != DDI_SUCCESS) {
1305 1305 FP_TRACE(FP_NHEAD2(9, 0),
1306 1306 "Failed to raise the power level");
1307 1307 return (DDI_FAILURE);
1308 1308 }
1309 1309 mutex_enter(&port->fp_mutex);
1310 1310 }
1311 1311 port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1312 1312 mutex_exit(&port->fp_mutex);
1313 1313
1314 1314 /*
1315 1315 * All the discovery is initiated and handled by per-port thread.
1316 1316 * Further all the discovery is done in handled in callback mode
1317 1317 * (not polled mode); In a specific case such as this, the discovery
1318 1318 * is required to happen in polled mode. The easiest way out is
1319 1319 * to bail out port thread and get started. Come back and fix this
1320 1320 * to do on demand discovery initiated by ULPs. ULPs such as FCP
1321 1321 * will do on-demand discovery during pre-power-up busctl handling
1322 1322 * which will only be possible when SCSA provides a new HBA vector
1323 1323 * for sending down the PM busctl requests.
1324 1324 */
1325 1325 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1326 1326
1327 1327 rval = fp_resume_all(port, FC_CMD_RESUME);
1328 1328 if (rval != DDI_SUCCESS) {
1329 1329 mutex_enter(&port->fp_mutex);
1330 1330 port->fp_soft_state |= FP_SOFT_SUSPEND;
1331 1331 mutex_exit(&port->fp_mutex);
1332 1332 (void) callb_generic_cpr(&port->fp_cpr_info,
1333 1333 CB_CODE_CPR_CHKPT);
1334 1334 }
1335 1335
1336 1336 return (rval);
1337 1337 }
1338 1338
1339 1339 /*
1340 1340 * Perform FC Port power on initialization
1341 1341 */
1342 1342 static int
1343 1343 fp_power_up(fc_local_port_t *port)
1344 1344 {
1345 1345 int rval;
1346 1346
1347 1347 ASSERT(MUTEX_HELD(&port->fp_mutex));
1348 1348
1349 1349 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1350 1350 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1351 1351
1352 1352 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1353 1353
1354 1354 mutex_exit(&port->fp_mutex);
1355 1355
1356 1356 rval = fp_resume_all(port, FC_CMD_POWER_UP);
1357 1357 if (rval != DDI_SUCCESS) {
1358 1358 mutex_enter(&port->fp_mutex);
1359 1359 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1360 1360 } else {
1361 1361 mutex_enter(&port->fp_mutex);
1362 1362 }
1363 1363
1364 1364 return (rval);
1365 1365 }
1366 1366
1367 1367
1368 1368 /*
1369 1369 * It is important to note that the power may possibly be removed between
1370 1370 * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1371 1371 * FC port hardware would have gone through an OFFLINE to ONLINE transition
1372 1372 * (hardware state). In this case, the port driver may need to rediscover the
1373 1373 * topology, perform LOGINs, register with the name server again and perform
1374 1374 * any such port initialization procedures. To perform LOGINs, the driver could
1375 1375 * use the port device handle to see if a LOGIN needs to be performed and use
1376 1376 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1377 1377 * or removed) which will be reflected in the map the ULPs will see.
1378 1378 */
1379 1379 static int
1380 1380 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1381 1381 {
1382 1382
1383 1383 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1384 1384
1385 1385 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1386 1386 return (DDI_FAILURE);
1387 1387 }
1388 1388
1389 1389 mutex_enter(&port->fp_mutex);
1390 1390
1391 1391 /*
1392 1392 * If there are commands queued for delayed retry, instead of
1393 1393 * working the hard way to figure out which ones are good for
1394 1394 * restart and which ones not (ELSs are definitely not good
1395 1395 * as the port will have to go through a new spin of rediscovery
1396 1396 * now), so just flush them out.
1397 1397 */
1398 1398 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1399 1399 fp_cmd_t *cmd;
1400 1400
1401 1401 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1402 1402
1403 1403 mutex_exit(&port->fp_mutex);
1404 1404 while ((cmd = fp_deque_cmd(port)) != NULL) {
1405 1405 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1406 1406 fp_iodone(cmd);
1407 1407 }
1408 1408 mutex_enter(&port->fp_mutex);
1409 1409 }
1410 1410
1411 1411 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1412 1412 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1413 1413 port->fp_dev_count) {
1414 1414 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1415 1415 port->fp_offline_tid = timeout(fp_offline_timeout,
1416 1416 (caddr_t)port, fp_offline_ticks);
1417 1417 }
1418 1418 if (port->fp_job_head) {
1419 1419 cv_signal(&port->fp_cv);
1420 1420 }
1421 1421 mutex_exit(&port->fp_mutex);
1422 1422 fctl_attach_ulps(port, cmd, &modlinkage);
1423 1423 } else {
1424 1424 struct job_request *job;
1425 1425
1426 1426 /*
1427 1427 * If an OFFLINE timer was running at the time of
1428 1428 * suspending, there is no need to restart it as
1429 1429 * the port is ONLINE now.
1430 1430 */
1431 1431 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1432 1432 if (port->fp_statec_busy == 0) {
1433 1433 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1434 1434 }
1435 1435 port->fp_statec_busy++;
1436 1436 mutex_exit(&port->fp_mutex);
1437 1437
1438 1438 job = fctl_alloc_job(JOB_PORT_ONLINE,
1439 1439 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1440 1440 fctl_enque_job(port, job);
1441 1441
1442 1442 fctl_jobwait(job);
1443 1443 fctl_remove_oldies(port);
1444 1444
1445 1445 fctl_attach_ulps(port, cmd, &modlinkage);
1446 1446 fctl_dealloc_job(job);
1447 1447 }
1448 1448
1449 1449 return (DDI_SUCCESS);
1450 1450 }
1451 1451
1452 1452
1453 1453 /*
1454 1454 * At this time, there shouldn't be any I/O requests on this port.
1455 1455 * But the unsolicited callbacks from the underlying FCA port need
1456 1456 * to be handled very carefully. The steps followed to handle the
1457 1457 * DDI_DETACH are:
1458 1458 * + Grab the port driver mutex, check if the unsolicited
1459 1459 * callback is currently under processing. If true, fail
1460 1460 * the DDI_DETACH request by printing a message; If false
1461 1461 * mark the DDI_DETACH as under progress, so that any
1462 1462 * further unsolicited callbacks get bounced.
1463 1463 * + Perform PRLO/LOGO if necessary, cleanup all the data
1464 1464 * structures.
1465 1465 * + Get the job_handler thread to gracefully exit.
1466 1466 * + Unregister callbacks with the FCA port.
1467 1467 * + Now that some peace is found, notify all the ULPs of
1468 1468 * DDI_DETACH request (using ulp_port_detach entry point)
1469 1469 * + Free all mutexes, semaphores, conditional variables.
1470 1470 * + Free the soft state, return success.
1471 1471 *
1472 1472 * Important considerations:
1473 1473 * Port driver de-registers state change and unsolicited
1474 1474 * callbacks before taking up the task of notifying ULPs
1475 1475 * and performing PRLO and LOGOs.
1476 1476 *
1477 1477 * A port may go offline at the time PRLO/LOGO is being
1478 1478 * requested. It is expected of all FCA drivers to fail
1479 1479 * such requests either immediately with a FC_OFFLINE
1480 1480 * return code to fc_fca_transport() or return the packet
1481 1481 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1482 1482 */
1483 1483 static int
1484 1484 fp_detach_handler(fc_local_port_t *port)
1485 1485 {
1486 1486 job_request_t *job;
1487 1487 uint32_t delay_count;
1488 1488 fc_orphan_t *orp, *tmporp;
1489 1489
1490 1490 /*
1491 1491 * In a Fabric topology with many host ports connected to
1492 1492 * a switch, another detaching instance of fp might have
1493 1493 * triggered a LOGO (which is an unsolicited request to
1494 1494 * this instance). So in order to be able to successfully
1495 1495 * detach by taking care of such cases a delay of about
1496 1496 * 30 seconds is introduced.
1497 1497 */
1498 1498 delay_count = 0;
1499 1499 mutex_enter(&port->fp_mutex);
1500 1500 if (port->fp_out_fpcmds != 0) {
1501 1501 /*
1502 1502 * At this time we can only check fp internal commands, because
1503 1503 * sd/ssd/scsi_vhci should have finsihed all their commands,
1504 1504 * fcp/fcip/fcsm should have finished all their commands.
1505 1505 *
1506 1506 * It seems that all fp internal commands are asynchronous now.
1507 1507 */
1508 1508 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1509 1509 mutex_exit(&port->fp_mutex);
1510 1510
1511 1511 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
1512 1512 " Failing detach", port->fp_instance, port->fp_out_fpcmds);
1513 1513 return (DDI_FAILURE);
1514 1514 }
1515 1515
1516 1516 while ((port->fp_soft_state &
1517 1517 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1518 1518 (delay_count < 30)) {
1519 1519 mutex_exit(&port->fp_mutex);
1520 1520 delay_count++;
1521 1521 delay(drv_usectohz(1000000));
1522 1522 mutex_enter(&port->fp_mutex);
1523 1523 }
1524 1524
1525 1525 if (port->fp_soft_state &
1526 1526 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1527 1527 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1528 1528 mutex_exit(&port->fp_mutex);
1529 1529
1530 1530 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1531 1531 " Failing detach", port->fp_instance);
1532 1532 return (DDI_FAILURE);
1533 1533 }
1534 1534
1535 1535 port->fp_soft_state |= FP_SOFT_IN_DETACH;
1536 1536 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1537 1537 mutex_exit(&port->fp_mutex);
1538 1538
1539 1539 /*
1540 1540 * If we're powered down, we need to raise power prior to submitting
1541 1541 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never
1542 1542 * process the shutdown job.
1543 1543 */
1544 1544 if (fctl_busy_port(port) != 0) {
1545 1545 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1546 1546 port->fp_instance);
1547 1547 mutex_enter(&port->fp_mutex);
1548 1548 port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1549 1549 mutex_exit(&port->fp_mutex);
1550 1550 return (DDI_FAILURE);
1551 1551 }
1552 1552
1553 1553 /*
1554 1554 * This will deallocate data structs and cause the "job" thread
1555 1555 * to exit, in preparation for DDI_DETACH on the instance.
1556 1556 * This can sleep for an arbitrary duration, since it waits for
1557 1557 * commands over the wire, timeout(9F) callbacks, etc.
1558 1558 *
1559 1559 * CAUTION: There is still a race here, where the "job" thread
1560 1560 * can still be executing code even tho the fctl_jobwait() call
1561 1561 * below has returned to us. In theory the fp driver could even be
1562 1562 * modunloaded even tho the job thread isn't done executing.
1563 1563 * without creating the race condition.
1564 1564 */
1565 1565 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1566 1566 (opaque_t)port, KM_SLEEP);
1567 1567 fctl_enque_job(port, job);
1568 1568 fctl_jobwait(job);
1569 1569 fctl_dealloc_job(job);
1570 1570
1571 1571
1572 1572 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1573 1573 FP_PM_PORT_DOWN);
1574 1574
1575 1575 if (port->fp_taskq) {
1576 1576 taskq_destroy(port->fp_taskq);
1577 1577 }
1578 1578
1579 1579 ddi_prop_remove_all(port->fp_port_dip);
1580 1580
1581 1581 ddi_remove_minor_node(port->fp_port_dip, NULL);
1582 1582
1583 1583 fctl_remove_port(port);
1584 1584
1585 1585 fp_free_pkt(port->fp_els_resp_pkt);
1586 1586
1587 1587 if (port->fp_ub_tokens) {
1588 1588 if (fc_ulp_ubfree(port, port->fp_ub_count,
1589 1589 port->fp_ub_tokens) != FC_SUCCESS) {
1590 1590 cmn_err(CE_WARN, "fp(%d): couldn't free "
1591 1591 " unsolicited buffers", port->fp_instance);
1592 1592 }
1593 1593 kmem_free(port->fp_ub_tokens,
1594 1594 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1595 1595 port->fp_ub_tokens = NULL;
1596 1596 }
1597 1597
1598 1598 if (port->fp_pkt_cache != NULL) {
1599 1599 kmem_cache_destroy(port->fp_pkt_cache);
1600 1600 }
1601 1601
1602 1602 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1603 1603
1604 1604 mutex_enter(&port->fp_mutex);
1605 1605 if (port->fp_did_table) {
1606 1606 kmem_free(port->fp_did_table, did_table_size *
1607 1607 sizeof (struct d_id_hash));
1608 1608 }
1609 1609
1610 1610 if (port->fp_pwwn_table) {
1611 1611 kmem_free(port->fp_pwwn_table, pwwn_table_size *
1612 1612 sizeof (struct pwwn_hash));
1613 1613 }
1614 1614 orp = port->fp_orphan_list;
1615 1615 while (orp) {
1616 1616 tmporp = orp;
1617 1617 orp = orp->orp_next;
1618 1618 kmem_free(tmporp, sizeof (*orp));
1619 1619 }
1620 1620
1621 1621 mutex_exit(&port->fp_mutex);
1622 1622
1623 1623 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1624 1624
1625 1625 mutex_destroy(&port->fp_mutex);
1626 1626 cv_destroy(&port->fp_attach_cv);
1627 1627 cv_destroy(&port->fp_cv);
1628 1628 ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1629 1629
1630 1630 return (DDI_SUCCESS);
1631 1631 }
1632 1632
1633 1633
1634 1634 /*
1635 1635 * Steps to perform DDI_SUSPEND operation on a FC port
1636 1636 *
1637 1637 * - If already suspended return DDI_FAILURE
1638 1638 * - If already power-suspended return DDI_SUCCESS
1639 1639 * - If an unsolicited callback or state change handling is in
1640 1640 * in progress, throw a warning message, return DDI_FAILURE
1641 1641 * - Cancel timeouts
1642 1642 * - SUSPEND the job_handler thread (means do nothing as it is
1643 1643 * taken care of by the CPR frame work)
1644 1644 */
1645 1645 static int
1646 1646 fp_suspend_handler(fc_local_port_t *port)
1647 1647 {
1648 1648 uint32_t delay_count;
1649 1649
1650 1650 mutex_enter(&port->fp_mutex);
1651 1651
1652 1652 /*
1653 1653 * The following should never happen, but
1654 1654 * let the driver be more defensive here
1655 1655 */
1656 1656 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1657 1657 mutex_exit(&port->fp_mutex);
1658 1658 return (DDI_FAILURE);
1659 1659 }
1660 1660
1661 1661 /*
1662 1662 * If the port is already power suspended, there
1663 1663 * is nothing else to do, So return DDI_SUCCESS,
1664 1664 * but mark the SUSPEND bit in the soft state
1665 1665 * before leaving.
1666 1666 */
1667 1667 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1668 1668 port->fp_soft_state |= FP_SOFT_SUSPEND;
1669 1669 mutex_exit(&port->fp_mutex);
1670 1670 return (DDI_SUCCESS);
1671 1671 }
1672 1672
1673 1673 /*
1674 1674 * Check if an unsolicited callback or state change handling is
1675 1675 * in progress. If true, fail the suspend operation; also throw
1676 1676 * a warning message notifying the failure. Note that Sun PCI
1677 1677 * hotplug spec recommends messages in cases of failure (but
1678 1678 * not flooding the console)
1679 1679 *
1680 1680 * Busy waiting for a short interval (500 millisecond ?) to see
1681 1681 * if the callback processing completes may be another idea. Since
1682 1682 * most of the callback processing involves a lot of work, it
1683 1683 * is safe to just fail the SUSPEND operation. It is definitely
1684 1684 * not bad to fail the SUSPEND operation if the driver is busy.
1685 1685 */
1686 1686 delay_count = 0;
1687 1687 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1688 1688 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1689 1689 mutex_exit(&port->fp_mutex);
1690 1690 delay_count++;
1691 1691 delay(drv_usectohz(1000000));
1692 1692 mutex_enter(&port->fp_mutex);
1693 1693 }
1694 1694
1695 1695 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1696 1696 FP_SOFT_IN_UNSOL_CB)) {
1697 1697 mutex_exit(&port->fp_mutex);
1698 1698 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1699 1699 " Failing suspend", port->fp_instance);
1700 1700 return (DDI_FAILURE);
1701 1701 }
1702 1702
1703 1703 /*
1704 1704 * Check of FC port thread is busy
1705 1705 */
1706 1706 if (port->fp_job_head) {
1707 1707 mutex_exit(&port->fp_mutex);
1708 1708 FP_TRACE(FP_NHEAD2(9, 0),
1709 1709 "FC port thread is busy: Failing suspend");
1710 1710 return (DDI_FAILURE);
1711 1711 }
1712 1712 port->fp_soft_state |= FP_SOFT_SUSPEND;
1713 1713
1714 1714 fp_suspend_all(port);
1715 1715 mutex_exit(&port->fp_mutex);
1716 1716
1717 1717 return (DDI_SUCCESS);
1718 1718 }
1719 1719
1720 1720
1721 1721 /*
1722 1722 * Prepare for graceful power down of a FC port
1723 1723 */
1724 1724 static int
1725 1725 fp_power_down(fc_local_port_t *port)
1726 1726 {
1727 1727 ASSERT(MUTEX_HELD(&port->fp_mutex));
1728 1728
1729 1729 /*
1730 1730 * Power down request followed by a DDI_SUSPEND should
1731 1731 * never happen; If it does return DDI_SUCCESS
1732 1732 */
1733 1733 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1734 1734 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1735 1735 return (DDI_SUCCESS);
1736 1736 }
1737 1737
1738 1738 /*
1739 1739 * If the port is already power suspended, there
1740 1740 * is nothing else to do, So return DDI_SUCCESS,
1741 1741 */
1742 1742 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1743 1743 return (DDI_SUCCESS);
1744 1744 }
1745 1745
1746 1746 /*
1747 1747 * Check if an unsolicited callback or state change handling
1748 1748 * is in progress. If true, fail the PM suspend operation.
1749 1749 * But don't print a message unless the verbosity of the
1750 1750 * driver desires otherwise.
1751 1751 */
1752 1752 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1753 1753 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1754 1754 FP_TRACE(FP_NHEAD2(9, 0),
1755 1755 "Unsolicited callback in progress: Failing power down");
1756 1756 return (DDI_FAILURE);
1757 1757 }
1758 1758
1759 1759 /*
1760 1760 * Check of FC port thread is busy
1761 1761 */
1762 1762 if (port->fp_job_head) {
1763 1763 FP_TRACE(FP_NHEAD2(9, 0),
1764 1764 "FC port thread is busy: Failing power down");
1765 1765 return (DDI_FAILURE);
1766 1766 }
1767 1767 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1768 1768
1769 1769 /*
1770 1770 * check if the ULPs are ready for power down
1771 1771 */
1772 1772 mutex_exit(&port->fp_mutex);
1773 1773 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1774 1774 &modlinkage) != FC_SUCCESS) {
1775 1775 mutex_enter(&port->fp_mutex);
1776 1776 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1777 1777 mutex_exit(&port->fp_mutex);
1778 1778
1779 1779 /*
1780 1780 * Power back up the obedient ULPs that went down
1781 1781 */
1782 1782 fp_attach_ulps(port, FC_CMD_POWER_UP);
1783 1783
1784 1784 FP_TRACE(FP_NHEAD2(9, 0),
1785 1785 "ULP(s) busy, detach_ulps failed. Failing power down");
1786 1786 mutex_enter(&port->fp_mutex);
1787 1787 return (DDI_FAILURE);
1788 1788 }
1789 1789 mutex_enter(&port->fp_mutex);
1790 1790
1791 1791 fp_suspend_all(port);
1792 1792
1793 1793 return (DDI_SUCCESS);
1794 1794 }
1795 1795
1796 1796
1797 1797 /*
1798 1798 * Suspend the entire FC port
1799 1799 */
1800 1800 static void
1801 1801 fp_suspend_all(fc_local_port_t *port)
1802 1802 {
1803 1803 int index;
1804 1804 struct pwwn_hash *head;
1805 1805 fc_remote_port_t *pd;
1806 1806
1807 1807 ASSERT(MUTEX_HELD(&port->fp_mutex));
1808 1808
1809 1809 if (port->fp_wait_tid != 0) {
1810 1810 timeout_id_t tid;
1811 1811
1812 1812 tid = port->fp_wait_tid;
1813 1813 port->fp_wait_tid = (timeout_id_t)NULL;
1814 1814 mutex_exit(&port->fp_mutex);
1815 1815 (void) untimeout(tid);
1816 1816 mutex_enter(&port->fp_mutex);
1817 1817 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1818 1818 }
1819 1819
1820 1820 if (port->fp_offline_tid) {
1821 1821 timeout_id_t tid;
1822 1822
1823 1823 tid = port->fp_offline_tid;
1824 1824 port->fp_offline_tid = (timeout_id_t)NULL;
1825 1825 mutex_exit(&port->fp_mutex);
1826 1826 (void) untimeout(tid);
1827 1827 mutex_enter(&port->fp_mutex);
1828 1828 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1829 1829 }
1830 1830 mutex_exit(&port->fp_mutex);
1831 1831 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1832 1832 mutex_enter(&port->fp_mutex);
1833 1833
1834 1834 /*
1835 1835 * Mark all devices as OLD, and reset the LOGIN state as well
1836 1836 * (this will force the ULPs to perform a LOGIN after calling
1837 1837 * fc_portgetmap() during RESUME/PM_RESUME)
1838 1838 */
1839 1839 for (index = 0; index < pwwn_table_size; index++) {
1840 1840 head = &port->fp_pwwn_table[index];
1841 1841 pd = head->pwwn_head;
1842 1842 while (pd != NULL) {
1843 1843 mutex_enter(&pd->pd_mutex);
1844 1844 fp_remote_port_offline(pd);
1845 1845 fctl_delist_did_table(port, pd);
1846 1846 pd->pd_state = PORT_DEVICE_VALID;
1847 1847 pd->pd_login_count = 0;
1848 1848 mutex_exit(&pd->pd_mutex);
1849 1849 pd = pd->pd_wwn_hnext;
1850 1850 }
1851 1851 }
1852 1852 }
1853 1853
1854 1854
1855 1855 /*
1856 1856 * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1857 1857 * Performs intializations for fc_packet_t structs.
1858 1858 * Returns 0 for success or -1 for failure.
1859 1859 *
1860 1860 * This function allocates DMA handles for both command and responses.
1861 1861 * Most of the ELSs used have both command and responses so it is strongly
1862 1862 * desired to move them to cache constructor routine.
1863 1863 *
1864 1864 * Context: Can sleep iff called with KM_SLEEP flag.
1865 1865 */
1866 1866 static int
1867 1867 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1868 1868 {
1869 1869 int (*cb) (caddr_t);
1870 1870 fc_packet_t *pkt;
1871 1871 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1872 1872 fc_local_port_t *port = (fc_local_port_t *)cdarg;
1873 1873
1874 1874 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1875 1875
1876 1876 cmd->cmd_next = NULL;
1877 1877 cmd->cmd_flags = 0;
1878 1878 cmd->cmd_dflags = 0;
1879 1879 cmd->cmd_job = NULL;
1880 1880 cmd->cmd_port = port;
1881 1881 pkt = &cmd->cmd_pkt;
1882 1882
1883 1883 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
1884 1884 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1885 1885 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1886 1886 &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1887 1887 return (-1);
1888 1888 }
1889 1889
1890 1890 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1891 1891 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1892 1892 &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1893 1893 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1894 1894 return (-1);
1895 1895 }
1896 1896 } else {
1897 1897 pkt->pkt_cmd_dma = 0;
1898 1898 pkt->pkt_resp_dma = 0;
1899 1899 }
1900 1900
1901 1901 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1902 1902 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1903 1903 pkt->pkt_data_cookie_cnt = 0;
1904 1904 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1905 1905 pkt->pkt_data_cookie = NULL;
1906 1906 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1907 1907
1908 1908 return (0);
1909 1909 }
1910 1910
1911 1911
1912 1912 /*
1913 1913 * fp_cache_destructor: Destructor function for kmem_cache_create().
1914 1914 * Performs un-intializations for fc_packet_t structs.
1915 1915 */
1916 1916 /* ARGSUSED */
1917 1917 static void
1918 1918 fp_cache_destructor(void *buf, void *cdarg)
1919 1919 {
1920 1920 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1921 1921 fc_packet_t *pkt;
1922 1922
1923 1923 pkt = &cmd->cmd_pkt;
1924 1924 if (pkt->pkt_cmd_dma) {
1925 1925 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1926 1926 }
1927 1927
1928 1928 if (pkt->pkt_resp_dma) {
1929 1929 ddi_dma_free_handle(&pkt->pkt_resp_dma);
1930 1930 }
1931 1931 }
1932 1932
1933 1933
1934 1934 /*
1935 1935 * Packet allocation for ELS and any other port driver commands
1936 1936 *
1937 1937 * Some ELSs like FLOGI and PLOGI are critical for topology and
1938 1938 * device discovery and a system's inability to allocate memory
1939 1939 * or DVMA resources while performing some of these critical ELSs
1940 1940 * cause a lot of problem. While memory allocation failures are
1941 1941 * rare, DVMA resource failures are common as the applications
1942 1942 * are becoming more and more powerful on huge servers. So it
1943 1943 * is desirable to have a framework support to reserve a fragment
1944 1944 * of DVMA. So until this is fixed the correct way, the suffering
1945 1945 * is huge whenever a LIP happens at a time DVMA resources are
1946 1946 * drained out completely - So an attempt needs to be made to
1947 1947 * KM_SLEEP while requesting for these resources, hoping that
1948 1948 * the requests won't hang forever.
1949 1949 *
1950 1950 * The fc_remote_port_t argument is stored into the pkt_pd field in the
1951 1951 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This
1952 1952 * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1953 1953 * If there is no fc_remote_port_t associated with the fc_packet_t, then
1954 1954 * fp_alloc_pkt() must be called with pd set to NULL.
1955 1955 *
1956 1956 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
1957 1957 * actually, it's a design fault. But there's no problem for physical
1958 1958 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
1959 1959 *
1960 1960 * For FCAs that don't support DMA, such as fcoei, we will use
1961 1961 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
1962 1962 */
1963 1963
1964 1964 static fp_cmd_t *
1965 1965 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1966 1966 fc_remote_port_t *pd)
1967 1967 {
1968 1968 int rval;
1969 1969 ulong_t real_len;
1970 1970 fp_cmd_t *cmd;
1971 1971 fc_packet_t *pkt;
1972 1972 int (*cb) (caddr_t);
1973 1973 ddi_dma_cookie_t pkt_cookie;
1974 1974 ddi_dma_cookie_t *cp;
1975 1975 uint32_t cnt;
1976 1976
1977 1977 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1978 1978
1979 1979 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1980 1980
1981 1981 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1982 1982 if (cmd == NULL) {
1983 1983 return (cmd);
1984 1984 }
1985 1985
1986 1986 cmd->cmd_ulp_pkt = NULL;
1987 1987 cmd->cmd_flags = 0;
1988 1988 pkt = &cmd->cmd_pkt;
1989 1989 ASSERT(cmd->cmd_dflags == 0);
1990 1990
1991 1991 pkt->pkt_datalen = 0;
1992 1992 pkt->pkt_data = NULL;
1993 1993 pkt->pkt_state = 0;
1994 1994 pkt->pkt_action = 0;
1995 1995 pkt->pkt_reason = 0;
1996 1996 pkt->pkt_expln = 0;
1997 1997 pkt->pkt_cmd = NULL;
1998 1998 pkt->pkt_resp = NULL;
1999 1999 pkt->pkt_fctl_rsvd1 = NULL;
2000 2000 pkt->pkt_fctl_rsvd2 = NULL;
2001 2001
2002 2002 /*
2003 2003 * Init pkt_pd with the given pointer; this must be done _before_
2004 2004 * the call to fc_ulp_init_packet().
2005 2005 */
2006 2006 pkt->pkt_pd = pd;
2007 2007
2008 2008 /* Now call the FCA driver to init its private, per-packet fields */
2009 2009 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
2010 2010 goto alloc_pkt_failed;
2011 2011 }
2012 2012
2013 2013 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2014 2014 ASSERT(pkt->pkt_cmd_dma != NULL);
2015 2015
2016 2016 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2017 2017 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
2018 2018 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2019 2019 &pkt->pkt_cmd_acc);
2020 2020
2021 2021 if (rval != DDI_SUCCESS) {
2022 2022 goto alloc_pkt_failed;
2023 2023 }
2024 2024 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
2025 2025
2026 2026 if (real_len < cmd_len) {
2027 2027 goto alloc_pkt_failed;
2028 2028 }
2029 2029
2030 2030 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2031 2031 pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2032 2032 DDI_DMA_CONSISTENT, cb, NULL,
2033 2033 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2034 2034
2035 2035 if (rval != DDI_DMA_MAPPED) {
2036 2036 goto alloc_pkt_failed;
2037 2037 }
2038 2038
2039 2039 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2040 2040
2041 2041 if (pkt->pkt_cmd_cookie_cnt >
2042 2042 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2043 2043 goto alloc_pkt_failed;
2044 2044 }
2045 2045
2046 2046 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2047 2047
2048 2048 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2049 2049 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2050 2050 KM_NOSLEEP);
2051 2051
2052 2052 if (cp == NULL) {
2053 2053 goto alloc_pkt_failed;
2054 2054 }
2055 2055
2056 2056 *cp = pkt_cookie;
2057 2057 cp++;
2058 2058 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2059 2059 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2060 2060 *cp = pkt_cookie;
2061 2061 }
2062 2062 } else if (cmd_len != 0) {
2063 2063 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
2064 2064 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
2065 2065 }
2066 2066
2067 2067 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2068 2068 ASSERT(pkt->pkt_resp_dma != NULL);
2069 2069
2070 2070 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2071 2071 port->fp_fca_tran->fca_acc_attr,
2072 2072 DDI_DMA_CONSISTENT, cb, NULL,
2073 2073 (caddr_t *)&pkt->pkt_resp, &real_len,
2074 2074 &pkt->pkt_resp_acc);
2075 2075
2076 2076 if (rval != DDI_SUCCESS) {
2077 2077 goto alloc_pkt_failed;
2078 2078 }
2079 2079 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2080 2080
2081 2081 if (real_len < resp_len) {
2082 2082 goto alloc_pkt_failed;
2083 2083 }
2084 2084
2085 2085 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2086 2086 pkt->pkt_resp, real_len, DDI_DMA_READ |
2087 2087 DDI_DMA_CONSISTENT, cb, NULL,
2088 2088 &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2089 2089
2090 2090 if (rval != DDI_DMA_MAPPED) {
2091 2091 goto alloc_pkt_failed;
2092 2092 }
2093 2093
2094 2094 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2095 2095
2096 2096 if (pkt->pkt_resp_cookie_cnt >
2097 2097 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2098 2098 goto alloc_pkt_failed;
2099 2099 }
2100 2100
2101 2101 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2102 2102
2103 2103 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2104 2104 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2105 2105 KM_NOSLEEP);
2106 2106
2107 2107 if (cp == NULL) {
2108 2108 goto alloc_pkt_failed;
2109 2109 }
2110 2110
2111 2111 *cp = pkt_cookie;
2112 2112 cp++;
2113 2113 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2114 2114 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2115 2115 *cp = pkt_cookie;
2116 2116 }
2117 2117 } else if (resp_len != 0) {
2118 2118 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
2119 2119 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
2120 2120 }
2121 2121
2122 2122 pkt->pkt_cmdlen = cmd_len;
2123 2123 pkt->pkt_rsplen = resp_len;
2124 2124 pkt->pkt_ulp_private = cmd;
2125 2125
2126 2126 return (cmd);
2127 2127
2128 2128 alloc_pkt_failed:
2129 2129
2130 2130 fp_free_dma(cmd);
2131 2131
2132 2132 if (pkt->pkt_cmd_cookie != NULL) {
2133 2133 kmem_free(pkt->pkt_cmd_cookie,
2134 2134 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2135 2135 pkt->pkt_cmd_cookie = NULL;
2136 2136 }
2137 2137
2138 2138 if (pkt->pkt_resp_cookie != NULL) {
2139 2139 kmem_free(pkt->pkt_resp_cookie,
2140 2140 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2141 2141 pkt->pkt_resp_cookie = NULL;
2142 2142 }
2143 2143
2144 2144 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2145 2145 if (pkt->pkt_cmd) {
2146 2146 kmem_free(pkt->pkt_cmd, cmd_len);
2147 2147 }
2148 2148
2149 2149 if (pkt->pkt_resp) {
2150 2150 kmem_free(pkt->pkt_resp, resp_len);
2151 2151 }
2152 2152 }
2153 2153
2154 2154 kmem_cache_free(port->fp_pkt_cache, cmd);
2155 2155
2156 2156 return (NULL);
2157 2157 }
2158 2158
2159 2159
2160 2160 /*
2161 2161 * Free FC packet
2162 2162 */
2163 2163 static void
2164 2164 fp_free_pkt(fp_cmd_t *cmd)
2165 2165 {
2166 2166 fc_local_port_t *port;
2167 2167 fc_packet_t *pkt;
2168 2168
2169 2169 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2170 2170
2171 2171 cmd->cmd_next = NULL;
2172 2172 cmd->cmd_job = NULL;
2173 2173 pkt = &cmd->cmd_pkt;
2174 2174 pkt->pkt_ulp_private = 0;
2175 2175 pkt->pkt_tran_flags = 0;
2176 2176 pkt->pkt_tran_type = 0;
2177 2177 port = cmd->cmd_port;
2178 2178
2179 2179 if (pkt->pkt_cmd_cookie != NULL) {
2180 2180 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2181 2181 sizeof (ddi_dma_cookie_t));
2182 2182 pkt->pkt_cmd_cookie = NULL;
2183 2183 }
2184 2184
2185 2185 if (pkt->pkt_resp_cookie != NULL) {
2186 2186 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2187 2187 sizeof (ddi_dma_cookie_t));
2188 2188 pkt->pkt_resp_cookie = NULL;
2189 2189 }
2190 2190
2191 2191 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2192 2192 if (pkt->pkt_cmd) {
2193 2193 kmem_free(pkt->pkt_cmd,
2194 2194 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
2195 2195 }
2196 2196
2197 2197 if (pkt->pkt_resp) {
2198 2198 kmem_free(pkt->pkt_resp,
2199 2199 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
2200 2200 }
2201 2201 }
2202 2202
2203 2203 fp_free_dma(cmd);
2204 2204 (void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2205 2205 kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2206 2206 }
2207 2207
2208 2208
2209 2209 /*
2210 2210 * Release DVMA resources
2211 2211 */
2212 2212 static void
2213 2213 fp_free_dma(fp_cmd_t *cmd)
2214 2214 {
2215 2215 fc_packet_t *pkt = &cmd->cmd_pkt;
2216 2216
2217 2217 pkt->pkt_cmdlen = 0;
2218 2218 pkt->pkt_rsplen = 0;
2219 2219 pkt->pkt_tran_type = 0;
2220 2220 pkt->pkt_tran_flags = 0;
2221 2221
2222 2222 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2223 2223 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2224 2224 }
2225 2225
2226 2226 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2227 2227 if (pkt->pkt_cmd_acc) {
2228 2228 ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2229 2229 }
2230 2230 }
2231 2231
2232 2232 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2233 2233 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2234 2234 }
2235 2235
2236 2236 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2237 2237 if (pkt->pkt_resp_acc) {
2238 2238 ddi_dma_mem_free(&pkt->pkt_resp_acc);
2239 2239 }
2240 2240 }
2241 2241 cmd->cmd_dflags = 0;
2242 2242 }
2243 2243
2244 2244
2245 2245 /*
2246 2246 * Dedicated thread to perform various activities. One thread for
2247 2247 * each fc_local_port_t (driver soft state) instance.
2248 2248 * Note, this effectively works out to one thread for each local
2249 2249 * port, but there are also some Solaris taskq threads in use on a per-local
↓ open down ↓ |
2249 lines elided |
↑ open up ↑ |
2250 2250 * port basis; these also need to be taken into consideration.
2251 2251 */
2252 2252 static void
2253 2253 fp_job_handler(fc_local_port_t *port)
2254 2254 {
2255 2255 int rval;
2256 2256 uint32_t *d_id;
2257 2257 fc_remote_port_t *pd;
2258 2258 job_request_t *job;
2259 2259
2260 -#ifndef __lock_lint
2261 2260 /*
2262 2261 * Solaris-internal stuff for proper operation of kernel threads
2263 2262 * with Solaris CPR.
2264 2263 */
2265 2264 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
2266 2265 callb_generic_cpr, "fp_job_handler");
2267 -#endif
2268 2266
2269 -
2270 2267 /* Loop forever waiting for work to do */
2271 2268 for (;;) {
2272 2269
2273 2270 mutex_enter(&port->fp_mutex);
2274 2271
2275 2272 /*
2276 2273 * Sleep if no work to do right now, or if we want
2277 2274 * to suspend or power-down.
2278 2275 */
2279 2276 while (port->fp_job_head == NULL ||
2280 2277 (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2281 2278 FP_SOFT_SUSPEND))) {
2282 2279 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2283 2280 cv_wait(&port->fp_cv, &port->fp_mutex);
2284 2281 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2285 2282 }
2286 2283
2287 2284 /*
2288 2285 * OK, we've just been woken up, so retrieve the next entry
2289 2286 * from the head of the job queue for this local port.
2290 2287 */
2291 2288 job = fctl_deque_job(port);
2292 2289
2293 2290 /*
2294 2291 * Handle all the fp driver's supported job codes here
2295 2292 * in this big honkin' switch.
2296 2293 */
2297 2294 switch (job->job_code) {
2298 2295 case JOB_PORT_SHUTDOWN:
2299 2296 /*
2300 2297 * fp_port_shutdown() is only called from here. This
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
2301 2298 * will prepare the local port instance (softstate)
2302 2299 * for detaching. This cancels timeout callbacks,
2303 2300 * executes LOGOs with remote ports, cleans up tables,
2304 2301 * and deallocates data structs.
2305 2302 */
2306 2303 fp_port_shutdown(port, job);
2307 2304
2308 2305 /*
2309 2306 * This will exit the job thread.
2310 2307 */
2311 -#ifndef __lock_lint
2312 2308 CALLB_CPR_EXIT(&(port->fp_cpr_info));
2313 -#else
2314 - mutex_exit(&port->fp_mutex);
2315 -#endif
2316 2309 fctl_jobdone(job);
2317 2310 thread_exit();
2318 2311
2319 2312 /* NOTREACHED */
2320 2313
2321 2314 case JOB_ATTACH_ULP: {
2322 2315 /*
2323 2316 * This job is spawned in response to a ULP calling
2324 2317 * fc_ulp_add().
2325 2318 */
2326 2319
2327 2320 boolean_t do_attach_ulps = B_TRUE;
2328 2321
2329 2322 /*
2330 2323 * If fp is detaching, we don't want to call
2331 2324 * fp_startup_done as this asynchronous
2332 2325 * notification may interfere with the re-attach.
2333 2326 */
2334 2327
2335 2328 if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2336 2329 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2337 2330 do_attach_ulps = B_FALSE;
2338 2331 } else {
2339 2332 /*
2340 2333 * We are going to force the transport
2341 2334 * to attach to the ULPs, so set
2342 2335 * fp_ulp_attach. This will keep any
2343 2336 * potential detach from occurring until
2344 2337 * we are done.
2345 2338 */
2346 2339 port->fp_ulp_attach = 1;
2347 2340 }
2348 2341
2349 2342 mutex_exit(&port->fp_mutex);
2350 2343
2351 2344 /*
2352 2345 * NOTE: Since we just dropped the mutex, there is now
2353 2346 * a race window where the fp_soft_state check above
2354 2347 * could change here. This race is covered because an
2355 2348 * additional check was added in the functions hidden
2356 2349 * under fp_startup_done().
2357 2350 */
2358 2351 if (do_attach_ulps == B_TRUE) {
2359 2352 /*
2360 2353 * This goes thru a bit of a convoluted call
2361 2354 * chain before spawning off a DDI taskq
2362 2355 * request to perform the actual attach
2363 2356 * operations. Blocking can occur at a number
2364 2357 * of points.
2365 2358 */
2366 2359 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2367 2360 }
2368 2361 job->job_result = FC_SUCCESS;
2369 2362 fctl_jobdone(job);
2370 2363 break;
2371 2364 }
2372 2365
2373 2366 case JOB_ULP_NOTIFY: {
2374 2367 /*
2375 2368 * Pass state change notifications up to any/all
2376 2369 * registered ULPs.
2377 2370 */
2378 2371 uint32_t statec;
2379 2372
2380 2373 statec = job->job_ulp_listlen;
2381 2374 if (statec == FC_STATE_RESET_REQUESTED) {
2382 2375 port->fp_last_task = port->fp_task;
2383 2376 port->fp_task = FP_TASK_OFFLINE;
2384 2377 fp_port_offline(port, 0);
2385 2378 port->fp_task = port->fp_last_task;
2386 2379 port->fp_last_task = FP_TASK_IDLE;
2387 2380 }
2388 2381
2389 2382 if (--port->fp_statec_busy == 0) {
2390 2383 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2391 2384 }
2392 2385
2393 2386 mutex_exit(&port->fp_mutex);
2394 2387
2395 2388 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2396 2389 fctl_jobdone(job);
2397 2390 break;
2398 2391 }
2399 2392
2400 2393 case JOB_PLOGI_ONE:
2401 2394 /*
2402 2395 * Issue a PLOGI to a single remote port. Multiple
2403 2396 * PLOGIs to different remote ports may occur in
2404 2397 * parallel.
2405 2398 * This can create the fc_remote_port_t if it does not
2406 2399 * already exist.
2407 2400 */
2408 2401
2409 2402 mutex_exit(&port->fp_mutex);
2410 2403 d_id = (uint32_t *)job->job_private;
2411 2404 pd = fctl_get_remote_port_by_did(port, *d_id);
2412 2405
2413 2406 if (pd) {
2414 2407 mutex_enter(&pd->pd_mutex);
2415 2408 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2416 2409 pd->pd_login_count++;
2417 2410 mutex_exit(&pd->pd_mutex);
2418 2411 job->job_result = FC_SUCCESS;
2419 2412 fctl_jobdone(job);
2420 2413 break;
2421 2414 }
2422 2415 mutex_exit(&pd->pd_mutex);
2423 2416 } else {
2424 2417 mutex_enter(&port->fp_mutex);
2425 2418 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2426 2419 mutex_exit(&port->fp_mutex);
2427 2420 pd = fp_create_remote_port_by_ns(port,
2428 2421 *d_id, KM_SLEEP);
2429 2422 if (pd == NULL) {
2430 2423 job->job_result = FC_FAILURE;
2431 2424 fctl_jobdone(job);
2432 2425 break;
2433 2426 }
2434 2427 } else {
2435 2428 mutex_exit(&port->fp_mutex);
2436 2429 }
2437 2430 }
2438 2431
2439 2432 job->job_flags |= JOB_TYPE_FP_ASYNC;
2440 2433 job->job_counter = 1;
2441 2434
2442 2435 rval = fp_port_login(port, *d_id, job,
2443 2436 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2444 2437
2445 2438 if (rval != FC_SUCCESS) {
2446 2439 job->job_result = rval;
2447 2440 fctl_jobdone(job);
2448 2441 }
↓ open down ↓ |
123 lines elided |
↑ open up ↑ |
2449 2442 break;
2450 2443
2451 2444 case JOB_LOGO_ONE: {
2452 2445 /*
2453 2446 * Issue a PLOGO to a single remote port. Multiple
2454 2447 * PLOGOs to different remote ports may occur in
2455 2448 * parallel.
2456 2449 */
2457 2450 fc_remote_port_t *pd;
2458 2451
2459 -#ifndef __lock_lint
2460 2452 ASSERT(job->job_counter > 0);
2461 -#endif
2462 2453
2463 2454 pd = (fc_remote_port_t *)job->job_ulp_pkts;
2464 2455
2465 2456 mutex_enter(&pd->pd_mutex);
2466 2457 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2467 2458 mutex_exit(&pd->pd_mutex);
2468 2459 job->job_result = FC_LOGINREQ;
2469 2460 mutex_exit(&port->fp_mutex);
2470 2461 fctl_jobdone(job);
2471 2462 break;
2472 2463 }
2473 2464 if (pd->pd_login_count > 1) {
2474 2465 pd->pd_login_count--;
2475 2466 mutex_exit(&pd->pd_mutex);
2476 2467 job->job_result = FC_SUCCESS;
2477 2468 mutex_exit(&port->fp_mutex);
2478 2469 fctl_jobdone(job);
2479 2470 break;
2480 2471 }
2481 2472 mutex_exit(&pd->pd_mutex);
2482 2473 mutex_exit(&port->fp_mutex);
2483 2474 job->job_flags |= JOB_TYPE_FP_ASYNC;
2484 2475 (void) fp_logout(port, pd, job);
2485 2476 break;
2486 2477 }
2487 2478
2488 2479 case JOB_FCIO_LOGIN:
2489 2480 /*
2490 2481 * PLOGI initiated at ioctl request.
2491 2482 */
2492 2483 mutex_exit(&port->fp_mutex);
2493 2484 job->job_result =
2494 2485 fp_fcio_login(port, job->job_private, job);
2495 2486 fctl_jobdone(job);
2496 2487 break;
2497 2488
2498 2489 case JOB_FCIO_LOGOUT:
2499 2490 /*
2500 2491 * PLOGO initiated at ioctl request.
2501 2492 */
2502 2493 mutex_exit(&port->fp_mutex);
2503 2494 job->job_result =
2504 2495 fp_fcio_logout(port, job->job_private, job);
2505 2496 fctl_jobdone(job);
2506 2497 break;
2507 2498
2508 2499 case JOB_PORT_GETMAP:
2509 2500 case JOB_PORT_GETMAP_PLOGI_ALL: {
2510 2501 port->fp_last_task = port->fp_task;
2511 2502 port->fp_task = FP_TASK_GETMAP;
2512 2503
2513 2504 switch (port->fp_topology) {
2514 2505 case FC_TOP_PRIVATE_LOOP:
2515 2506 job->job_counter = 1;
2516 2507
2517 2508 fp_get_loopmap(port, job);
2518 2509 mutex_exit(&port->fp_mutex);
2519 2510 fp_jobwait(job);
2520 2511 fctl_fillout_map(port,
2521 2512 (fc_portmap_t **)job->job_private,
2522 2513 (uint32_t *)job->job_arg, 1, 0, 0);
2523 2514 fctl_jobdone(job);
2524 2515 mutex_enter(&port->fp_mutex);
2525 2516 break;
2526 2517
2527 2518 case FC_TOP_PUBLIC_LOOP:
2528 2519 case FC_TOP_FABRIC:
2529 2520 mutex_exit(&port->fp_mutex);
2530 2521 job->job_counter = 1;
2531 2522
2532 2523 job->job_result = fp_ns_getmap(port,
2533 2524 job, (fc_portmap_t **)job->job_private,
2534 2525 (uint32_t *)job->job_arg,
2535 2526 FCTL_GAN_START_ID);
2536 2527 fctl_jobdone(job);
2537 2528 mutex_enter(&port->fp_mutex);
2538 2529 break;
2539 2530
2540 2531 case FC_TOP_PT_PT:
2541 2532 mutex_exit(&port->fp_mutex);
2542 2533 fctl_fillout_map(port,
2543 2534 (fc_portmap_t **)job->job_private,
2544 2535 (uint32_t *)job->job_arg, 1, 0, 0);
2545 2536 fctl_jobdone(job);
2546 2537 mutex_enter(&port->fp_mutex);
2547 2538 break;
2548 2539
2549 2540 default:
2550 2541 mutex_exit(&port->fp_mutex);
2551 2542 fctl_jobdone(job);
2552 2543 mutex_enter(&port->fp_mutex);
2553 2544 break;
2554 2545 }
2555 2546 port->fp_task = port->fp_last_task;
2556 2547 port->fp_last_task = FP_TASK_IDLE;
2557 2548 mutex_exit(&port->fp_mutex);
2558 2549 break;
2559 2550 }
2560 2551
2561 2552 case JOB_PORT_OFFLINE: {
2562 2553 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2563 2554
2564 2555 port->fp_last_task = port->fp_task;
2565 2556 port->fp_task = FP_TASK_OFFLINE;
2566 2557
2567 2558 if (port->fp_statec_busy > 2) {
2568 2559 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2569 2560 fp_port_offline(port, 0);
2570 2561 if (--port->fp_statec_busy == 0) {
2571 2562 port->fp_soft_state &=
2572 2563 ~FP_SOFT_IN_STATEC_CB;
2573 2564 }
2574 2565 } else {
2575 2566 fp_port_offline(port, 1);
2576 2567 }
2577 2568
2578 2569 port->fp_task = port->fp_last_task;
2579 2570 port->fp_last_task = FP_TASK_IDLE;
2580 2571
2581 2572 mutex_exit(&port->fp_mutex);
2582 2573
2583 2574 fctl_jobdone(job);
2584 2575 break;
2585 2576 }
2586 2577
2587 2578 case JOB_PORT_STARTUP: {
2588 2579 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2589 2580 if (port->fp_statec_busy > 1) {
2590 2581 mutex_exit(&port->fp_mutex);
2591 2582 break;
2592 2583 }
2593 2584 mutex_exit(&port->fp_mutex);
2594 2585
2595 2586 FP_TRACE(FP_NHEAD2(9, rval),
2596 2587 "Topology discovery failed");
2597 2588 break;
2598 2589 }
2599 2590
2600 2591 /*
2601 2592 * Attempt building device handles in case
2602 2593 * of private Loop.
2603 2594 */
2604 2595 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2605 2596 job->job_counter = 1;
2606 2597
2607 2598 fp_get_loopmap(port, job);
2608 2599 mutex_exit(&port->fp_mutex);
2609 2600 fp_jobwait(job);
2610 2601 mutex_enter(&port->fp_mutex);
2611 2602 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2612 2603 ASSERT(port->fp_total_devices == 0);
2613 2604 port->fp_total_devices =
2614 2605 port->fp_dev_count;
2615 2606 }
2616 2607 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2617 2608 /*
2618 2609 * Hack to avoid state changes going up early
2619 2610 */
2620 2611 port->fp_statec_busy++;
2621 2612 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2622 2613
2623 2614 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2624 2615 fp_fabric_online(port, job);
2625 2616 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2626 2617 }
2627 2618 mutex_exit(&port->fp_mutex);
2628 2619 fctl_jobdone(job);
2629 2620 break;
2630 2621 }
2631 2622
2632 2623 case JOB_PORT_ONLINE: {
2633 2624 char *newtop;
2634 2625 char *oldtop;
2635 2626 uint32_t old_top;
2636 2627
2637 2628 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2638 2629
2639 2630 /*
2640 2631 * Bail out early if there are a lot of
2641 2632 * state changes in the pipeline
2642 2633 */
2643 2634 if (port->fp_statec_busy > 1) {
2644 2635 --port->fp_statec_busy;
2645 2636 mutex_exit(&port->fp_mutex);
2646 2637 fctl_jobdone(job);
2647 2638 break;
2648 2639 }
2649 2640
2650 2641 switch (old_top = port->fp_topology) {
2651 2642 case FC_TOP_PRIVATE_LOOP:
2652 2643 oldtop = "Private Loop";
2653 2644 break;
2654 2645
2655 2646 case FC_TOP_PUBLIC_LOOP:
2656 2647 oldtop = "Public Loop";
2657 2648 break;
2658 2649
2659 2650 case FC_TOP_PT_PT:
2660 2651 oldtop = "Point to Point";
2661 2652 break;
2662 2653
2663 2654 case FC_TOP_FABRIC:
2664 2655 oldtop = "Fabric";
2665 2656 break;
2666 2657
2667 2658 default:
2668 2659 oldtop = NULL;
2669 2660 break;
2670 2661 }
2671 2662
2672 2663 port->fp_last_task = port->fp_task;
2673 2664 port->fp_task = FP_TASK_ONLINE;
2674 2665
2675 2666 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2676 2667
2677 2668 port->fp_task = port->fp_last_task;
2678 2669 port->fp_last_task = FP_TASK_IDLE;
2679 2670
2680 2671 if (port->fp_statec_busy > 1) {
2681 2672 --port->fp_statec_busy;
2682 2673 mutex_exit(&port->fp_mutex);
2683 2674 break;
2684 2675 }
2685 2676
2686 2677 port->fp_state = FC_STATE_OFFLINE;
2687 2678
2688 2679 FP_TRACE(FP_NHEAD2(9, rval),
2689 2680 "Topology discovery failed");
2690 2681
2691 2682 if (--port->fp_statec_busy == 0) {
2692 2683 port->fp_soft_state &=
2693 2684 ~FP_SOFT_IN_STATEC_CB;
2694 2685 }
2695 2686
2696 2687 if (port->fp_offline_tid == NULL) {
2697 2688 port->fp_offline_tid =
2698 2689 timeout(fp_offline_timeout,
2699 2690 (caddr_t)port, fp_offline_ticks);
2700 2691 }
2701 2692
2702 2693 mutex_exit(&port->fp_mutex);
2703 2694 break;
2704 2695 }
2705 2696
2706 2697 switch (port->fp_topology) {
2707 2698 case FC_TOP_PRIVATE_LOOP:
2708 2699 newtop = "Private Loop";
2709 2700 break;
2710 2701
2711 2702 case FC_TOP_PUBLIC_LOOP:
2712 2703 newtop = "Public Loop";
2713 2704 break;
2714 2705
2715 2706 case FC_TOP_PT_PT:
2716 2707 newtop = "Point to Point";
2717 2708 break;
2718 2709
2719 2710 case FC_TOP_FABRIC:
2720 2711 newtop = "Fabric";
2721 2712 break;
2722 2713
2723 2714 default:
2724 2715 newtop = NULL;
2725 2716 break;
2726 2717 }
2727 2718
2728 2719 if (oldtop && newtop && strcmp(oldtop, newtop)) {
2729 2720 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2730 2721 "Change in FC Topology old = %s new = %s",
2731 2722 oldtop, newtop);
2732 2723 }
2733 2724
2734 2725 switch (port->fp_topology) {
2735 2726 case FC_TOP_PRIVATE_LOOP: {
2736 2727 int orphan = (old_top == FC_TOP_FABRIC ||
2737 2728 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2738 2729
2739 2730 mutex_exit(&port->fp_mutex);
2740 2731 fp_loop_online(port, job, orphan);
2741 2732 break;
2742 2733 }
2743 2734
2744 2735 case FC_TOP_PUBLIC_LOOP:
2745 2736 /* FALLTHROUGH */
2746 2737 case FC_TOP_FABRIC:
2747 2738 fp_fabric_online(port, job);
2748 2739 mutex_exit(&port->fp_mutex);
2749 2740 break;
2750 2741
2751 2742 case FC_TOP_PT_PT:
2752 2743 fp_p2p_online(port, job);
2753 2744 mutex_exit(&port->fp_mutex);
2754 2745 break;
2755 2746
2756 2747 default:
2757 2748 if (--port->fp_statec_busy != 0) {
2758 2749 /*
2759 2750 * Watch curiously at what the next
2760 2751 * state transition can do.
2761 2752 */
2762 2753 mutex_exit(&port->fp_mutex);
2763 2754 break;
2764 2755 }
2765 2756
2766 2757 FP_TRACE(FP_NHEAD2(9, 0),
2767 2758 "Topology Unknown, Offlining the port..");
2768 2759
2769 2760 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2770 2761 port->fp_state = FC_STATE_OFFLINE;
2771 2762
2772 2763 if (port->fp_offline_tid == NULL) {
2773 2764 port->fp_offline_tid =
2774 2765 timeout(fp_offline_timeout,
2775 2766 (caddr_t)port, fp_offline_ticks);
2776 2767 }
2777 2768 mutex_exit(&port->fp_mutex);
2778 2769 break;
2779 2770 }
2780 2771
2781 2772 mutex_enter(&port->fp_mutex);
2782 2773
2783 2774 port->fp_task = port->fp_last_task;
2784 2775 port->fp_last_task = FP_TASK_IDLE;
2785 2776
2786 2777 mutex_exit(&port->fp_mutex);
2787 2778
2788 2779 fctl_jobdone(job);
2789 2780 break;
2790 2781 }
2791 2782
2792 2783 case JOB_PLOGI_GROUP: {
2793 2784 mutex_exit(&port->fp_mutex);
2794 2785 fp_plogi_group(port, job);
2795 2786 break;
2796 2787 }
2797 2788
2798 2789 case JOB_UNSOL_REQUEST: {
2799 2790 mutex_exit(&port->fp_mutex);
2800 2791 fp_handle_unsol_buf(port,
2801 2792 (fc_unsol_buf_t *)job->job_private, job);
2802 2793 fctl_dealloc_job(job);
2803 2794 break;
2804 2795 }
2805 2796
2806 2797 case JOB_NS_CMD: {
2807 2798 fctl_ns_req_t *ns_cmd;
2808 2799
2809 2800 mutex_exit(&port->fp_mutex);
2810 2801
2811 2802 job->job_flags |= JOB_TYPE_FP_ASYNC;
2812 2803 ns_cmd = (fctl_ns_req_t *)job->job_private;
2813 2804 if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2814 2805 ns_cmd->ns_cmd_code > NS_DA_ID) {
2815 2806 job->job_result = FC_BADCMD;
2816 2807 fctl_jobdone(job);
2817 2808 break;
2818 2809 }
2819 2810
2820 2811 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2821 2812 if (ns_cmd->ns_pd != NULL) {
2822 2813 job->job_result = FC_BADOBJECT;
2823 2814 fctl_jobdone(job);
2824 2815 break;
2825 2816 }
2826 2817
2827 2818 job->job_counter = 1;
2828 2819
2829 2820 rval = fp_ns_reg(port, ns_cmd->ns_pd,
2830 2821 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2831 2822
2832 2823 if (rval != FC_SUCCESS) {
2833 2824 job->job_result = rval;
2834 2825 fctl_jobdone(job);
2835 2826 }
2836 2827 break;
2837 2828 }
2838 2829 job->job_result = FC_SUCCESS;
2839 2830 job->job_counter = 1;
2840 2831
2841 2832 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2842 2833 if (rval != FC_SUCCESS) {
2843 2834 fctl_jobdone(job);
2844 2835 }
2845 2836 break;
2846 2837 }
2847 2838
2848 2839 case JOB_LINK_RESET: {
2849 2840 la_wwn_t *pwwn;
2850 2841 uint32_t topology;
2851 2842
2852 2843 pwwn = (la_wwn_t *)job->job_private;
2853 2844 ASSERT(pwwn != NULL);
2854 2845
2855 2846 topology = port->fp_topology;
2856 2847 mutex_exit(&port->fp_mutex);
2857 2848
2858 2849 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2859 2850 topology == FC_TOP_PRIVATE_LOOP) {
2860 2851 job->job_flags |= JOB_TYPE_FP_ASYNC;
2861 2852 rval = port->fp_fca_tran->fca_reset(
2862 2853 port->fp_fca_handle, FC_FCA_LINK_RESET);
2863 2854 job->job_result = rval;
2864 2855 fp_jobdone(job);
2865 2856 } else {
2866 2857 ASSERT((job->job_flags &
2867 2858 JOB_TYPE_FP_ASYNC) == 0);
2868 2859
2869 2860 if (FC_IS_TOP_SWITCH(topology)) {
2870 2861 rval = fp_remote_lip(port, pwwn,
2871 2862 KM_SLEEP, job);
2872 2863 } else {
2873 2864 rval = FC_FAILURE;
2874 2865 }
2875 2866 if (rval != FC_SUCCESS) {
2876 2867 job->job_result = rval;
2877 2868 }
2878 2869 fctl_jobdone(job);
2879 2870 }
2880 2871 break;
2881 2872 }
2882 2873
2883 2874 default:
2884 2875 mutex_exit(&port->fp_mutex);
2885 2876 job->job_result = FC_BADCMD;
2886 2877 fctl_jobdone(job);
2887 2878 break;
2888 2879 }
2889 2880 }
2890 2881 /* NOTREACHED */
2891 2882 }
2892 2883
2893 2884
2894 2885 /*
2895 2886 * Perform FC port bring up initialization
2896 2887 */
2897 2888 static int
2898 2889 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2899 2890 {
2900 2891 int rval;
2901 2892 uint32_t state;
2902 2893 uint32_t src_id;
2903 2894 fc_lilpmap_t *lilp_map;
2904 2895
2905 2896 ASSERT(MUTEX_HELD(&port->fp_mutex));
2906 2897 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2907 2898
2908 2899 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2909 2900 " port=%p, job=%p", port, job);
2910 2901
2911 2902 port->fp_topology = FC_TOP_UNKNOWN;
2912 2903 port->fp_port_id.port_id = 0;
2913 2904 state = FC_PORT_STATE_MASK(port->fp_state);
2914 2905
2915 2906 if (state == FC_STATE_OFFLINE) {
2916 2907 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2917 2908 job->job_result = FC_OFFLINE;
2918 2909 mutex_exit(&port->fp_mutex);
2919 2910 fctl_jobdone(job);
2920 2911 mutex_enter(&port->fp_mutex);
2921 2912 return (FC_OFFLINE);
2922 2913 }
2923 2914
2924 2915 if (state == FC_STATE_LOOP) {
2925 2916 port->fp_port_type.port_type = FC_NS_PORT_NL;
2926 2917 mutex_exit(&port->fp_mutex);
2927 2918
2928 2919 lilp_map = &port->fp_lilp_map;
2929 2920 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2930 2921 job->job_result = FC_FAILURE;
2931 2922 fctl_jobdone(job);
2932 2923
2933 2924 FP_TRACE(FP_NHEAD1(9, rval),
2934 2925 "LILP map Invalid or not present");
2935 2926 mutex_enter(&port->fp_mutex);
2936 2927 return (FC_FAILURE);
2937 2928 }
2938 2929
2939 2930 if (lilp_map->lilp_length == 0) {
2940 2931 job->job_result = FC_NO_MAP;
2941 2932 fctl_jobdone(job);
2942 2933 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2943 2934 "LILP map length zero");
2944 2935 mutex_enter(&port->fp_mutex);
2945 2936 return (FC_NO_MAP);
2946 2937 }
2947 2938 src_id = lilp_map->lilp_myalpa & 0xFF;
2948 2939 } else {
2949 2940 fc_remote_port_t *pd;
2950 2941 fc_fca_pm_t pm;
2951 2942 fc_fca_p2p_info_t p2p_info;
2952 2943 int pd_recepient;
2953 2944
2954 2945 /*
2955 2946 * Get P2P remote port info if possible
2956 2947 */
2957 2948 bzero((caddr_t)&pm, sizeof (pm));
2958 2949
2959 2950 pm.pm_cmd_flags = FC_FCA_PM_READ;
2960 2951 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2961 2952 pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2962 2953 pm.pm_data_buf = (caddr_t)&p2p_info;
2963 2954
2964 2955 rval = port->fp_fca_tran->fca_port_manage(
2965 2956 port->fp_fca_handle, &pm);
2966 2957
2967 2958 if (rval == FC_SUCCESS) {
2968 2959 port->fp_port_id.port_id = p2p_info.fca_d_id;
2969 2960 port->fp_port_type.port_type = FC_NS_PORT_N;
2970 2961 port->fp_topology = FC_TOP_PT_PT;
2971 2962 port->fp_total_devices = 1;
2972 2963 pd_recepient = fctl_wwn_cmp(
2973 2964 &port->fp_service_params.nport_ww_name,
2974 2965 &p2p_info.pwwn) < 0 ?
2975 2966 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2976 2967 mutex_exit(&port->fp_mutex);
2977 2968 pd = fctl_create_remote_port(port,
2978 2969 &p2p_info.nwwn,
2979 2970 &p2p_info.pwwn,
2980 2971 p2p_info.d_id,
2981 2972 pd_recepient, KM_NOSLEEP);
2982 2973 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2983 2974 " P2P port=%p pd=%p fp %x pd %x", port, pd,
2984 2975 port->fp_port_id.port_id, p2p_info.d_id);
2985 2976 mutex_enter(&port->fp_mutex);
2986 2977 return (FC_SUCCESS);
2987 2978 }
2988 2979 port->fp_port_type.port_type = FC_NS_PORT_N;
2989 2980 mutex_exit(&port->fp_mutex);
2990 2981 src_id = 0;
2991 2982 }
2992 2983
2993 2984 job->job_counter = 1;
2994 2985 job->job_result = FC_SUCCESS;
2995 2986
2996 2987 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2997 2988 KM_SLEEP)) != FC_SUCCESS) {
2998 2989 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2999 2990 job->job_result = FC_FAILURE;
3000 2991 fctl_jobdone(job);
3001 2992
3002 2993 mutex_enter(&port->fp_mutex);
3003 2994 if (port->fp_statec_busy <= 1) {
3004 2995 mutex_exit(&port->fp_mutex);
3005 2996 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
3006 2997 "Couldn't transport FLOGI");
3007 2998 mutex_enter(&port->fp_mutex);
3008 2999 }
3009 3000 return (FC_FAILURE);
3010 3001 }
3011 3002
3012 3003 fp_jobwait(job);
3013 3004
3014 3005 mutex_enter(&port->fp_mutex);
3015 3006 if (job->job_result == FC_SUCCESS) {
3016 3007 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3017 3008 mutex_exit(&port->fp_mutex);
3018 3009 fp_ns_init(port, job, KM_SLEEP);
3019 3010 mutex_enter(&port->fp_mutex);
3020 3011 }
3021 3012 } else {
3022 3013 if (state == FC_STATE_LOOP) {
3023 3014 port->fp_topology = FC_TOP_PRIVATE_LOOP;
3024 3015 port->fp_port_id.port_id =
3025 3016 port->fp_lilp_map.lilp_myalpa & 0xFF;
3026 3017 }
3027 3018 }
3028 3019
3029 3020 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
3030 3021 port, job);
3031 3022
3032 3023 return (FC_SUCCESS);
3033 3024 }
3034 3025
3035 3026
3036 3027 /*
3037 3028 * Perform ULP invocations following FC port startup
3038 3029 */
3039 3030 /* ARGSUSED */
3040 3031 static void
3041 3032 fp_startup_done(opaque_t arg, uchar_t result)
3042 3033 {
3043 3034 fc_local_port_t *port = arg;
3044 3035
3045 3036 fp_attach_ulps(port, FC_CMD_ATTACH);
3046 3037
3047 3038 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
3048 3039 }
3049 3040
3050 3041
3051 3042 /*
3052 3043 * Perform ULP port attach
3053 3044 */
3054 3045 static void
3055 3046 fp_ulp_port_attach(void *arg)
3056 3047 {
3057 3048 fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
3058 3049 fc_local_port_t *port = att->att_port;
3059 3050
3060 3051 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3061 3052 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3062 3053
3063 3054 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3064 3055
3065 3056 if (att->att_need_pm_idle == B_TRUE) {
3066 3057 fctl_idle_port(port);
3067 3058 }
3068 3059
3069 3060 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3070 3061 " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3071 3062
3072 3063 mutex_enter(&att->att_port->fp_mutex);
3073 3064 att->att_port->fp_ulp_attach = 0;
3074 3065
3075 3066 port->fp_task = port->fp_last_task;
3076 3067 port->fp_last_task = FP_TASK_IDLE;
3077 3068
3078 3069 cv_signal(&att->att_port->fp_attach_cv);
3079 3070
3080 3071 mutex_exit(&att->att_port->fp_mutex);
3081 3072
3082 3073 kmem_free(att, sizeof (fp_soft_attach_t));
3083 3074 }
3084 3075
3085 3076 /*
3086 3077 * Entry point to funnel all requests down to FCAs
3087 3078 */
3088 3079 static int
3089 3080 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3090 3081 {
3091 3082 int rval;
3092 3083
3093 3084 mutex_enter(&port->fp_mutex);
3094 3085 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3095 3086 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3096 3087 FC_STATE_OFFLINE))) {
3097 3088 /*
3098 3089 * This means there is more than one state change
3099 3090 * at this point of time - Since they are processed
3100 3091 * serially, any processing of the current one should
3101 3092 * be failed, failed and move up in processing the next
3102 3093 */
3103 3094 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3104 3095 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3105 3096 if (cmd->cmd_job) {
3106 3097 /*
3107 3098 * A state change that is going to be invalidated
3108 3099 * by another one already in the port driver's queue
3109 3100 * need not go up to all ULPs. This will minimize
3110 3101 * needless processing and ripples in ULP modules
3111 3102 */
3112 3103 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3113 3104 }
3114 3105 mutex_exit(&port->fp_mutex);
3115 3106 return (FC_STATEC_BUSY);
3116 3107 }
3117 3108
3118 3109 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3119 3110 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3120 3111 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3121 3112 mutex_exit(&port->fp_mutex);
3122 3113
3123 3114 return (FC_OFFLINE);
3124 3115 }
3125 3116 mutex_exit(&port->fp_mutex);
3126 3117
3127 3118 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3128 3119 if (rval != FC_SUCCESS) {
3129 3120 if (rval == FC_TRAN_BUSY) {
3130 3121 cmd->cmd_retry_interval = fp_retry_delay;
3131 3122 rval = fp_retry_cmd(&cmd->cmd_pkt);
3132 3123 if (rval == FC_FAILURE) {
3133 3124 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3134 3125 }
3135 3126 }
3136 3127 } else {
3137 3128 mutex_enter(&port->fp_mutex);
3138 3129 port->fp_out_fpcmds++;
3139 3130 mutex_exit(&port->fp_mutex);
3140 3131 }
3141 3132
3142 3133 return (rval);
3143 3134 }
3144 3135
3145 3136
3146 3137 /*
3147 3138 * Each time a timeout kicks in, walk the wait queue, decrement the
3148 3139 * the retry_interval, when the retry_interval becomes less than
3149 3140 * or equal to zero, re-transport the command: If the re-transport
3150 3141 * fails with BUSY, enqueue the command in the wait queue.
3151 3142 *
3152 3143 * In order to prevent looping forever because of commands enqueued
3153 3144 * from within this function itself, save the current tail pointer
3154 3145 * (in cur_tail) and exit the loop after serving this command.
3155 3146 */
3156 3147 static void
3157 3148 fp_resendcmd(void *port_handle)
3158 3149 {
3159 3150 int rval;
3160 3151 fc_local_port_t *port;
3161 3152 fp_cmd_t *cmd;
3162 3153 fp_cmd_t *cur_tail;
3163 3154
3164 3155 port = port_handle;
3165 3156 mutex_enter(&port->fp_mutex);
3166 3157 cur_tail = port->fp_wait_tail;
3167 3158 mutex_exit(&port->fp_mutex);
3168 3159
3169 3160 while ((cmd = fp_deque_cmd(port)) != NULL) {
3170 3161 cmd->cmd_retry_interval -= fp_retry_ticker;
3171 3162 /* Check if we are detaching */
3172 3163 if (port->fp_soft_state &
3173 3164 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3174 3165 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3175 3166 cmd->cmd_pkt.pkt_reason = 0;
3176 3167 fp_iodone(cmd);
3177 3168 } else if (cmd->cmd_retry_interval <= 0) {
3178 3169 rval = cmd->cmd_transport(port->fp_fca_handle,
3179 3170 &cmd->cmd_pkt);
3180 3171
3181 3172 if (rval != FC_SUCCESS) {
3182 3173 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3183 3174 if (--cmd->cmd_retry_count) {
3184 3175 fp_enque_cmd(port, cmd);
3185 3176 if (cmd == cur_tail) {
3186 3177 break;
3187 3178 }
3188 3179 continue;
3189 3180 }
3190 3181 cmd->cmd_pkt.pkt_state =
3191 3182 FC_PKT_TRAN_BSY;
3192 3183 } else {
3193 3184 cmd->cmd_pkt.pkt_state =
3194 3185 FC_PKT_TRAN_ERROR;
3195 3186 }
3196 3187 cmd->cmd_pkt.pkt_reason = 0;
3197 3188 fp_iodone(cmd);
3198 3189 } else {
3199 3190 mutex_enter(&port->fp_mutex);
3200 3191 port->fp_out_fpcmds++;
3201 3192 mutex_exit(&port->fp_mutex);
3202 3193 }
3203 3194 } else {
3204 3195 fp_enque_cmd(port, cmd);
3205 3196 }
3206 3197
3207 3198 if (cmd == cur_tail) {
3208 3199 break;
3209 3200 }
3210 3201 }
3211 3202
3212 3203 mutex_enter(&port->fp_mutex);
3213 3204 if (port->fp_wait_head) {
3214 3205 timeout_id_t tid;
3215 3206
3216 3207 mutex_exit(&port->fp_mutex);
3217 3208 tid = timeout(fp_resendcmd, (caddr_t)port,
3218 3209 fp_retry_ticks);
3219 3210 mutex_enter(&port->fp_mutex);
3220 3211 port->fp_wait_tid = tid;
3221 3212 } else {
3222 3213 port->fp_wait_tid = NULL;
3223 3214 }
3224 3215 mutex_exit(&port->fp_mutex);
3225 3216 }
3226 3217
3227 3218
3228 3219 /*
3229 3220 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3230 3221 *
3231 3222 * Yes, as you can see below, cmd_retry_count is used here too. That means
3232 3223 * the retries for BUSY are less if there were transport failures (transport
3233 3224 * failure means fca_transport failure). The goal is not to exceed overall
3234 3225 * retries set in the cmd_retry_count (whatever may be the reason for retry)
3235 3226 *
3236 3227 * Return Values:
3237 3228 * FC_SUCCESS
3238 3229 * FC_FAILURE
3239 3230 */
3240 3231 static int
3241 3232 fp_retry_cmd(fc_packet_t *pkt)
3242 3233 {
3243 3234 fp_cmd_t *cmd;
3244 3235
3245 3236 cmd = pkt->pkt_ulp_private;
3246 3237
3247 3238 if (--cmd->cmd_retry_count) {
3248 3239 fp_enque_cmd(cmd->cmd_port, cmd);
3249 3240 return (FC_SUCCESS);
3250 3241 } else {
3251 3242 return (FC_FAILURE);
3252 3243 }
3253 3244 }
3254 3245
3255 3246
3256 3247 /*
3257 3248 * Queue up FC packet for deferred retry
3258 3249 */
3259 3250 static void
3260 3251 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3261 3252 {
3262 3253 timeout_id_t tid;
3263 3254
3264 3255 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3265 3256
3266 3257 #ifdef DEBUG
3267 3258 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3268 3259 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3269 3260 #endif
3270 3261
3271 3262 mutex_enter(&port->fp_mutex);
3272 3263 if (port->fp_wait_tail) {
3273 3264 port->fp_wait_tail->cmd_next = cmd;
3274 3265 port->fp_wait_tail = cmd;
3275 3266 } else {
3276 3267 ASSERT(port->fp_wait_head == NULL);
3277 3268 port->fp_wait_head = port->fp_wait_tail = cmd;
3278 3269 if (port->fp_wait_tid == NULL) {
3279 3270 mutex_exit(&port->fp_mutex);
3280 3271 tid = timeout(fp_resendcmd, (caddr_t)port,
3281 3272 fp_retry_ticks);
3282 3273 mutex_enter(&port->fp_mutex);
3283 3274 port->fp_wait_tid = tid;
3284 3275 }
3285 3276 }
3286 3277 mutex_exit(&port->fp_mutex);
3287 3278 }
3288 3279
3289 3280
3290 3281 /*
3291 3282 * Handle all RJT codes
3292 3283 */
3293 3284 static int
3294 3285 fp_handle_reject(fc_packet_t *pkt)
3295 3286 {
3296 3287 int rval = FC_FAILURE;
3297 3288 uchar_t next_class;
3298 3289 fp_cmd_t *cmd;
3299 3290 fc_local_port_t *port;
3300 3291
3301 3292 cmd = pkt->pkt_ulp_private;
3302 3293 port = cmd->cmd_port;
3303 3294
3304 3295 switch (pkt->pkt_state) {
3305 3296 case FC_PKT_FABRIC_RJT:
3306 3297 case FC_PKT_NPORT_RJT:
3307 3298 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3308 3299 next_class = fp_get_nextclass(cmd->cmd_port,
3309 3300 FC_TRAN_CLASS(pkt->pkt_tran_flags));
3310 3301
3311 3302 if (next_class == FC_TRAN_CLASS_INVALID) {
3312 3303 return (rval);
3313 3304 }
3314 3305 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3315 3306 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3316 3307
3317 3308 rval = fp_sendcmd(cmd->cmd_port, cmd,
3318 3309 cmd->cmd_port->fp_fca_handle);
3319 3310
3320 3311 if (rval != FC_SUCCESS) {
3321 3312 pkt->pkt_state = FC_PKT_TRAN_ERROR;
3322 3313 }
3323 3314 }
3324 3315 break;
3325 3316
3326 3317 case FC_PKT_LS_RJT:
3327 3318 case FC_PKT_BA_RJT:
3328 3319 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3329 3320 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3330 3321 cmd->cmd_retry_interval = fp_retry_delay;
3331 3322 rval = fp_retry_cmd(pkt);
3332 3323 }
3333 3324 break;
3334 3325
3335 3326 case FC_PKT_FS_RJT:
3336 3327 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
3337 3328 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
3338 3329 (pkt->pkt_expln == 0x00))) {
3339 3330 cmd->cmd_retry_interval = fp_retry_delay;
3340 3331 rval = fp_retry_cmd(pkt);
3341 3332 }
3342 3333 break;
3343 3334
3344 3335 case FC_PKT_LOCAL_RJT:
3345 3336 if (pkt->pkt_reason == FC_REASON_QFULL) {
3346 3337 cmd->cmd_retry_interval = fp_retry_delay;
3347 3338 rval = fp_retry_cmd(pkt);
3348 3339 }
3349 3340 break;
3350 3341
3351 3342 default:
3352 3343 FP_TRACE(FP_NHEAD1(1, 0),
3353 3344 "fp_handle_reject(): Invalid pkt_state");
3354 3345 break;
3355 3346 }
3356 3347
3357 3348 return (rval);
3358 3349 }
3359 3350
3360 3351
3361 3352 /*
3362 3353 * Return the next class of service supported by the FCA
3363 3354 */
3364 3355 static uchar_t
3365 3356 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3366 3357 {
3367 3358 uchar_t next_class;
3368 3359
3369 3360 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3370 3361
3371 3362 switch (cur_class) {
3372 3363 case FC_TRAN_CLASS_INVALID:
3373 3364 if (port->fp_cos & FC_NS_CLASS1) {
3374 3365 next_class = FC_TRAN_CLASS1;
3375 3366 break;
3376 3367 }
3377 3368 /* FALLTHROUGH */
3378 3369
3379 3370 case FC_TRAN_CLASS1:
3380 3371 if (port->fp_cos & FC_NS_CLASS2) {
3381 3372 next_class = FC_TRAN_CLASS2;
3382 3373 break;
3383 3374 }
3384 3375 /* FALLTHROUGH */
3385 3376
3386 3377 case FC_TRAN_CLASS2:
3387 3378 if (port->fp_cos & FC_NS_CLASS3) {
3388 3379 next_class = FC_TRAN_CLASS3;
3389 3380 break;
3390 3381 }
3391 3382 /* FALLTHROUGH */
3392 3383
3393 3384 case FC_TRAN_CLASS3:
3394 3385 default:
3395 3386 next_class = FC_TRAN_CLASS_INVALID;
3396 3387 break;
3397 3388 }
3398 3389
3399 3390 return (next_class);
3400 3391 }
3401 3392
3402 3393
3403 3394 /*
3404 3395 * Determine if a class of service is supported by the FCA
3405 3396 */
3406 3397 static int
3407 3398 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3408 3399 {
3409 3400 int rval;
3410 3401
3411 3402 switch (tran_class) {
3412 3403 case FC_TRAN_CLASS1:
3413 3404 if (cos & FC_NS_CLASS1) {
3414 3405 rval = FC_SUCCESS;
3415 3406 } else {
3416 3407 rval = FC_FAILURE;
3417 3408 }
3418 3409 break;
3419 3410
3420 3411 case FC_TRAN_CLASS2:
3421 3412 if (cos & FC_NS_CLASS2) {
3422 3413 rval = FC_SUCCESS;
3423 3414 } else {
3424 3415 rval = FC_FAILURE;
3425 3416 }
3426 3417 break;
3427 3418
3428 3419 case FC_TRAN_CLASS3:
3429 3420 if (cos & FC_NS_CLASS3) {
3430 3421 rval = FC_SUCCESS;
3431 3422 } else {
3432 3423 rval = FC_FAILURE;
3433 3424 }
3434 3425 break;
3435 3426
3436 3427 default:
3437 3428 rval = FC_FAILURE;
3438 3429 break;
3439 3430 }
3440 3431
3441 3432 return (rval);
3442 3433 }
3443 3434
3444 3435
3445 3436 /*
3446 3437 * Dequeue FC packet for retry
3447 3438 */
3448 3439 static fp_cmd_t *
3449 3440 fp_deque_cmd(fc_local_port_t *port)
3450 3441 {
3451 3442 fp_cmd_t *cmd;
3452 3443
3453 3444 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3454 3445
3455 3446 mutex_enter(&port->fp_mutex);
3456 3447
3457 3448 if (port->fp_wait_head == NULL) {
3458 3449 /*
3459 3450 * To avoid races, NULL the fp_wait_tid as
3460 3451 * we are about to exit the timeout thread.
3461 3452 */
3462 3453 port->fp_wait_tid = NULL;
3463 3454 mutex_exit(&port->fp_mutex);
3464 3455 return (NULL);
3465 3456 }
3466 3457
3467 3458 cmd = port->fp_wait_head;
3468 3459 port->fp_wait_head = cmd->cmd_next;
3469 3460 cmd->cmd_next = NULL;
3470 3461
3471 3462 if (port->fp_wait_head == NULL) {
3472 3463 port->fp_wait_tail = NULL;
3473 3464 }
3474 3465 mutex_exit(&port->fp_mutex);
3475 3466
3476 3467 return (cmd);
3477 3468 }
3478 3469
3479 3470
3480 3471 /*
3481 3472 * Wait for job completion
3482 3473 */
3483 3474 static void
3484 3475 fp_jobwait(job_request_t *job)
3485 3476 {
3486 3477 sema_p(&job->job_port_sema);
3487 3478 }
3488 3479
3489 3480
3490 3481 /*
3491 3482 * Convert FC packet state to FC errno
3492 3483 */
3493 3484 int
3494 3485 fp_state_to_rval(uchar_t state)
3495 3486 {
3496 3487 int count;
3497 3488
3498 3489 for (count = 0; count < sizeof (fp_xlat) /
3499 3490 sizeof (fp_xlat[0]); count++) {
3500 3491 if (fp_xlat[count].xlat_state == state) {
3501 3492 return (fp_xlat[count].xlat_rval);
3502 3493 }
3503 3494 }
3504 3495
3505 3496 return (FC_FAILURE);
3506 3497 }
3507 3498
3508 3499
3509 3500 /*
3510 3501 * For Synchronous I/O requests, the caller is
3511 3502 * expected to do fctl_jobdone(if necessary)
3512 3503 *
3513 3504 * We want to preserve at least one failure in the
3514 3505 * job_result if it happens.
3515 3506 *
3516 3507 */
3517 3508 static void
3518 3509 fp_iodone(fp_cmd_t *cmd)
3519 3510 {
3520 3511 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt;
3521 3512 job_request_t *job = cmd->cmd_job;
3522 3513 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd;
3523 3514
3524 3515 ASSERT(job != NULL);
3525 3516 ASSERT(cmd->cmd_port != NULL);
3526 3517 ASSERT(&cmd->cmd_pkt != NULL);
3527 3518
3528 3519 mutex_enter(&job->job_mutex);
3529 3520 if (job->job_result == FC_SUCCESS) {
3530 3521 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3531 3522 }
3532 3523 mutex_exit(&job->job_mutex);
3533 3524
3534 3525 if (pd) {
3535 3526 mutex_enter(&pd->pd_mutex);
3536 3527 pd->pd_flags = PD_IDLE;
3537 3528 mutex_exit(&pd->pd_mutex);
3538 3529 }
3539 3530
3540 3531 if (ulp_pkt) {
3541 3532 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3542 3533 FP_IS_PKT_ERROR(ulp_pkt)) {
3543 3534 fc_local_port_t *port;
3544 3535 fc_remote_node_t *node;
3545 3536
3546 3537 port = cmd->cmd_port;
3547 3538
3548 3539 mutex_enter(&pd->pd_mutex);
3549 3540 pd->pd_state = PORT_DEVICE_INVALID;
3550 3541 pd->pd_ref_count--;
3551 3542 node = pd->pd_remote_nodep;
3552 3543 mutex_exit(&pd->pd_mutex);
3553 3544
3554 3545 ASSERT(node != NULL);
3555 3546 ASSERT(port != NULL);
3556 3547
3557 3548 if (fctl_destroy_remote_port(port, pd) == 0) {
3558 3549 fctl_destroy_remote_node(node);
3559 3550 }
3560 3551
3561 3552 ulp_pkt->pkt_pd = NULL;
3562 3553 }
3563 3554
3564 3555 ulp_pkt->pkt_comp(ulp_pkt);
3565 3556 }
3566 3557
3567 3558 fp_free_pkt(cmd);
3568 3559 fp_jobdone(job);
3569 3560 }
3570 3561
3571 3562
3572 3563 /*
3573 3564 * Job completion handler
3574 3565 */
3575 3566 static void
3576 3567 fp_jobdone(job_request_t *job)
3577 3568 {
3578 3569 mutex_enter(&job->job_mutex);
3579 3570 ASSERT(job->job_counter > 0);
3580 3571
3581 3572 if (--job->job_counter != 0) {
3582 3573 mutex_exit(&job->job_mutex);
3583 3574 return;
3584 3575 }
3585 3576
3586 3577 if (job->job_ulp_pkts) {
3587 3578 ASSERT(job->job_ulp_listlen > 0);
3588 3579 kmem_free(job->job_ulp_pkts,
3589 3580 sizeof (fc_packet_t *) * job->job_ulp_listlen);
3590 3581 }
3591 3582
3592 3583 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3593 3584 mutex_exit(&job->job_mutex);
3594 3585 fctl_jobdone(job);
3595 3586 } else {
3596 3587 mutex_exit(&job->job_mutex);
3597 3588 sema_v(&job->job_port_sema);
3598 3589 }
3599 3590 }
3600 3591
3601 3592
3602 3593 /*
3603 3594 * Try to perform shutdown of a port during a detach. No return
3604 3595 * value since the detach should not fail because the port shutdown
3605 3596 * failed.
3606 3597 */
3607 3598 static void
3608 3599 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3609 3600 {
3610 3601 int index;
3611 3602 int count;
3612 3603 int flags;
3613 3604 fp_cmd_t *cmd;
3614 3605 struct pwwn_hash *head;
3615 3606 fc_remote_port_t *pd;
3616 3607
3617 3608 ASSERT(MUTEX_HELD(&port->fp_mutex));
3618 3609
3619 3610 job->job_result = FC_SUCCESS;
3620 3611
3621 3612 if (port->fp_taskq) {
3622 3613 /*
3623 3614 * We must release the mutex here to ensure that other
3624 3615 * potential jobs can complete their processing. Many
3625 3616 * also need this mutex.
3626 3617 */
3627 3618 mutex_exit(&port->fp_mutex);
3628 3619 taskq_wait(port->fp_taskq);
3629 3620 mutex_enter(&port->fp_mutex);
3630 3621 }
3631 3622
3632 3623 if (port->fp_offline_tid) {
3633 3624 timeout_id_t tid;
3634 3625
3635 3626 tid = port->fp_offline_tid;
3636 3627 port->fp_offline_tid = NULL;
3637 3628 mutex_exit(&port->fp_mutex);
3638 3629 (void) untimeout(tid);
3639 3630 mutex_enter(&port->fp_mutex);
3640 3631 }
3641 3632
3642 3633 if (port->fp_wait_tid) {
3643 3634 timeout_id_t tid;
3644 3635
3645 3636 tid = port->fp_wait_tid;
3646 3637 port->fp_wait_tid = NULL;
3647 3638 mutex_exit(&port->fp_mutex);
3648 3639 (void) untimeout(tid);
3649 3640 } else {
3650 3641 mutex_exit(&port->fp_mutex);
3651 3642 }
3652 3643
3653 3644 /*
3654 3645 * While we cancel the timeout, let's also return the
3655 3646 * the outstanding requests back to the callers.
3656 3647 */
3657 3648 while ((cmd = fp_deque_cmd(port)) != NULL) {
3658 3649 ASSERT(cmd->cmd_job != NULL);
3659 3650 cmd->cmd_job->job_result = FC_OFFLINE;
3660 3651 fp_iodone(cmd);
3661 3652 }
3662 3653
3663 3654 /*
3664 3655 * Gracefully LOGO with all the devices logged in.
3665 3656 */
3666 3657 mutex_enter(&port->fp_mutex);
3667 3658
3668 3659 for (count = index = 0; index < pwwn_table_size; index++) {
3669 3660 head = &port->fp_pwwn_table[index];
3670 3661 pd = head->pwwn_head;
3671 3662 while (pd != NULL) {
3672 3663 mutex_enter(&pd->pd_mutex);
3673 3664 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3674 3665 count++;
3675 3666 }
3676 3667 mutex_exit(&pd->pd_mutex);
3677 3668 pd = pd->pd_wwn_hnext;
3678 3669 }
3679 3670 }
3680 3671
3681 3672 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3682 3673 flags = job->job_flags;
3683 3674 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3684 3675 } else {
3685 3676 flags = 0;
3686 3677 }
3687 3678 if (count) {
3688 3679 job->job_counter = count;
3689 3680
3690 3681 for (index = 0; index < pwwn_table_size; index++) {
3691 3682 head = &port->fp_pwwn_table[index];
3692 3683 pd = head->pwwn_head;
3693 3684 while (pd != NULL) {
3694 3685 mutex_enter(&pd->pd_mutex);
3695 3686 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3696 3687 ASSERT(pd->pd_login_count > 0);
3697 3688 /*
3698 3689 * Force the counter to ONE in order
3699 3690 * for us to really send LOGO els.
3700 3691 */
3701 3692 pd->pd_login_count = 1;
3702 3693 mutex_exit(&pd->pd_mutex);
3703 3694 mutex_exit(&port->fp_mutex);
3704 3695 (void) fp_logout(port, pd, job);
3705 3696 mutex_enter(&port->fp_mutex);
3706 3697 } else {
3707 3698 mutex_exit(&pd->pd_mutex);
3708 3699 }
3709 3700 pd = pd->pd_wwn_hnext;
3710 3701 }
3711 3702 }
3712 3703 mutex_exit(&port->fp_mutex);
3713 3704 fp_jobwait(job);
3714 3705 } else {
3715 3706 mutex_exit(&port->fp_mutex);
3716 3707 }
3717 3708
3718 3709 if (job->job_result != FC_SUCCESS) {
3719 3710 FP_TRACE(FP_NHEAD1(9, 0),
3720 3711 "Can't logout all devices. Proceeding with"
3721 3712 " port shutdown");
3722 3713 job->job_result = FC_SUCCESS;
3723 3714 }
3724 3715
3725 3716 fctl_destroy_all_remote_ports(port);
3726 3717
3727 3718 mutex_enter(&port->fp_mutex);
3728 3719 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3729 3720 mutex_exit(&port->fp_mutex);
3730 3721 fp_ns_fini(port, job);
3731 3722 } else {
3732 3723 mutex_exit(&port->fp_mutex);
3733 3724 }
3734 3725
3735 3726 if (flags) {
3736 3727 job->job_flags = flags;
3737 3728 }
3738 3729
3739 3730 mutex_enter(&port->fp_mutex);
3740 3731
3741 3732 }
3742 3733
3743 3734
3744 3735 /*
3745 3736 * Build the port driver's data structures based on the AL_PA list
3746 3737 */
3747 3738 static void
3748 3739 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3749 3740 {
3750 3741 int rval;
3751 3742 int flag;
3752 3743 int count;
3753 3744 uint32_t d_id;
3754 3745 fc_remote_port_t *pd;
3755 3746 fc_lilpmap_t *lilp_map;
3756 3747
3757 3748 ASSERT(MUTEX_HELD(&port->fp_mutex));
3758 3749
3759 3750 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3760 3751 job->job_result = FC_OFFLINE;
3761 3752 mutex_exit(&port->fp_mutex);
3762 3753 fp_jobdone(job);
3763 3754 mutex_enter(&port->fp_mutex);
3764 3755 return;
3765 3756 }
3766 3757
3767 3758 if (port->fp_lilp_map.lilp_length == 0) {
3768 3759 mutex_exit(&port->fp_mutex);
3769 3760 job->job_result = FC_NO_MAP;
3770 3761 fp_jobdone(job);
3771 3762 mutex_enter(&port->fp_mutex);
3772 3763 return;
3773 3764 }
3774 3765 mutex_exit(&port->fp_mutex);
3775 3766
3776 3767 lilp_map = &port->fp_lilp_map;
3777 3768 job->job_counter = lilp_map->lilp_length;
3778 3769
3779 3770 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3780 3771 flag = FP_CMD_PLOGI_RETAIN;
3781 3772 } else {
3782 3773 flag = FP_CMD_PLOGI_DONT_CARE;
3783 3774 }
3784 3775
3785 3776 for (count = 0; count < lilp_map->lilp_length; count++) {
3786 3777 d_id = lilp_map->lilp_alpalist[count];
3787 3778
3788 3779 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3789 3780 fp_jobdone(job);
3790 3781 continue;
3791 3782 }
3792 3783
3793 3784 pd = fctl_get_remote_port_by_did(port, d_id);
3794 3785 if (pd) {
3795 3786 mutex_enter(&pd->pd_mutex);
3796 3787 if (flag == FP_CMD_PLOGI_DONT_CARE ||
3797 3788 pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3798 3789 mutex_exit(&pd->pd_mutex);
3799 3790 fp_jobdone(job);
3800 3791 continue;
3801 3792 }
3802 3793 mutex_exit(&pd->pd_mutex);
3803 3794 }
3804 3795
3805 3796 rval = fp_port_login(port, d_id, job, flag,
3806 3797 KM_SLEEP, pd, NULL);
3807 3798 if (rval != FC_SUCCESS) {
3808 3799 fp_jobdone(job);
3809 3800 }
3810 3801 }
3811 3802
3812 3803 mutex_enter(&port->fp_mutex);
3813 3804 }
3814 3805
3815 3806
3816 3807 /*
3817 3808 * Perform loop ONLINE processing
3818 3809 */
3819 3810 static void
3820 3811 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3821 3812 {
3822 3813 int count;
3823 3814 int rval;
3824 3815 uint32_t d_id;
3825 3816 uint32_t listlen;
3826 3817 fc_lilpmap_t *lilp_map;
3827 3818 fc_remote_port_t *pd;
3828 3819 fc_portmap_t *changelist;
3829 3820
3830 3821 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3831 3822
3832 3823 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3833 3824 port, job);
3834 3825
3835 3826 lilp_map = &port->fp_lilp_map;
3836 3827
3837 3828 if (lilp_map->lilp_length) {
3838 3829 mutex_enter(&port->fp_mutex);
3839 3830 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3840 3831 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3841 3832 mutex_exit(&port->fp_mutex);
3842 3833 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3843 3834 } else {
3844 3835 mutex_exit(&port->fp_mutex);
3845 3836 }
3846 3837
3847 3838 job->job_counter = lilp_map->lilp_length;
3848 3839
3849 3840 for (count = 0; count < lilp_map->lilp_length; count++) {
3850 3841 d_id = lilp_map->lilp_alpalist[count];
3851 3842
3852 3843 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3853 3844 fp_jobdone(job);
3854 3845 continue;
3855 3846 }
3856 3847
3857 3848 pd = fctl_get_remote_port_by_did(port, d_id);
3858 3849 if (pd != NULL) {
3859 3850 #ifdef DEBUG
3860 3851 mutex_enter(&pd->pd_mutex);
3861 3852 if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3862 3853 ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3863 3854 }
3864 3855 mutex_exit(&pd->pd_mutex);
3865 3856 #endif
3866 3857 fp_jobdone(job);
3867 3858 continue;
3868 3859 }
3869 3860
3870 3861 rval = fp_port_login(port, d_id, job,
3871 3862 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3872 3863
3873 3864 if (rval != FC_SUCCESS) {
3874 3865 fp_jobdone(job);
3875 3866 }
3876 3867 }
3877 3868 fp_jobwait(job);
3878 3869 }
3879 3870 listlen = 0;
3880 3871 changelist = NULL;
3881 3872
3882 3873 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3883 3874 mutex_enter(&port->fp_mutex);
3884 3875 ASSERT(port->fp_statec_busy > 0);
3885 3876 if (port->fp_statec_busy == 1) {
3886 3877 mutex_exit(&port->fp_mutex);
3887 3878 fctl_fillout_map(port, &changelist, &listlen,
3888 3879 1, 0, orphan);
3889 3880
3890 3881 mutex_enter(&port->fp_mutex);
3891 3882 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3892 3883 ASSERT(port->fp_total_devices == 0);
3893 3884 port->fp_total_devices = port->fp_dev_count;
3894 3885 }
3895 3886 } else {
3896 3887 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3897 3888 }
3898 3889 mutex_exit(&port->fp_mutex);
3899 3890 }
3900 3891
3901 3892 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3902 3893 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3903 3894 listlen, listlen, KM_SLEEP);
3904 3895 } else {
3905 3896 mutex_enter(&port->fp_mutex);
3906 3897 if (--port->fp_statec_busy == 0) {
3907 3898 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3908 3899 }
3909 3900 ASSERT(changelist == NULL && listlen == 0);
3910 3901 mutex_exit(&port->fp_mutex);
3911 3902 }
3912 3903
3913 3904 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3914 3905 port, job);
3915 3906 }
3916 3907
3917 3908
3918 3909 /*
3919 3910 * Get an Arbitrated Loop map from the underlying FCA
3920 3911 */
3921 3912 static int
3922 3913 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3923 3914 {
3924 3915 int rval;
3925 3916
3926 3917 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3927 3918 port, lilp_map);
3928 3919
3929 3920 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3930 3921 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3931 3922 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */
3932 3923
3933 3924 if (rval != FC_SUCCESS) {
3934 3925 rval = FC_NO_MAP;
3935 3926 } else if (lilp_map->lilp_length == 0 &&
3936 3927 (lilp_map->lilp_magic >= MAGIC_LISM &&
3937 3928 lilp_map->lilp_magic < MAGIC_LIRP)) {
3938 3929 uchar_t lilp_length;
3939 3930
3940 3931 /*
3941 3932 * Since the map length is zero, provide all
3942 3933 * the valid AL_PAs for NL_ports discovery.
3943 3934 */
3944 3935 lilp_length = sizeof (fp_valid_alpas) /
3945 3936 sizeof (fp_valid_alpas[0]);
3946 3937 lilp_map->lilp_length = lilp_length;
3947 3938 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3948 3939 lilp_length);
3949 3940 } else {
3950 3941 rval = fp_validate_lilp_map(lilp_map);
3951 3942
3952 3943 if (rval == FC_SUCCESS) {
3953 3944 mutex_enter(&port->fp_mutex);
3954 3945 port->fp_total_devices = lilp_map->lilp_length - 1;
3955 3946 mutex_exit(&port->fp_mutex);
3956 3947 }
3957 3948 }
3958 3949
3959 3950 mutex_enter(&port->fp_mutex);
3960 3951 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3961 3952 port->fp_soft_state |= FP_SOFT_BAD_LINK;
3962 3953 mutex_exit(&port->fp_mutex);
3963 3954
3964 3955 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3965 3956 FC_FCA_RESET_CORE) != FC_SUCCESS) {
3966 3957 FP_TRACE(FP_NHEAD1(9, 0),
3967 3958 "FCA reset failed after LILP map was found"
3968 3959 " to be invalid");
3969 3960 }
3970 3961 } else if (rval == FC_SUCCESS) {
3971 3962 port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3972 3963 mutex_exit(&port->fp_mutex);
3973 3964 } else {
3974 3965 mutex_exit(&port->fp_mutex);
3975 3966 }
3976 3967
3977 3968 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3978 3969 lilp_map);
3979 3970
3980 3971 return (rval);
3981 3972 }
3982 3973
3983 3974
3984 3975 /*
3985 3976 * Perform Fabric Login:
3986 3977 *
3987 3978 * Return Values:
3988 3979 * FC_SUCCESS
3989 3980 * FC_FAILURE
3990 3981 * FC_NOMEM
3991 3982 * FC_TRANSPORT_ERROR
3992 3983 * and a lot others defined in fc_error.h
3993 3984 */
3994 3985 static int
3995 3986 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3996 3987 int flag, int sleep)
3997 3988 {
3998 3989 int rval;
3999 3990 fp_cmd_t *cmd;
4000 3991 uchar_t class;
4001 3992
4002 3993 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4003 3994
4004 3995 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
4005 3996 port, job);
4006 3997
4007 3998 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4008 3999 if (class == FC_TRAN_CLASS_INVALID) {
4009 4000 return (FC_ELS_BAD);
4010 4001 }
4011 4002
4012 4003 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4013 4004 sizeof (la_els_logi_t), sleep, NULL);
4014 4005 if (cmd == NULL) {
4015 4006 return (FC_NOMEM);
4016 4007 }
4017 4008
4018 4009 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4019 4010 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4020 4011 cmd->cmd_flags = flag;
4021 4012 cmd->cmd_retry_count = fp_retry_count;
4022 4013 cmd->cmd_ulp_pkt = NULL;
4023 4014
4024 4015 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
4025 4016 job, LA_ELS_FLOGI);
4026 4017
4027 4018 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
4028 4019 if (rval != FC_SUCCESS) {
4029 4020 fp_free_pkt(cmd);
4030 4021 }
4031 4022
4032 4023 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
4033 4024 port, job);
4034 4025
4035 4026 return (rval);
4036 4027 }
4037 4028
4038 4029
4039 4030 /*
4040 4031 * In some scenarios such as private loop device discovery period
4041 4032 * the fc_remote_port_t data structure isn't allocated. The allocation
4042 4033 * is done when the PLOGI is successful. In some other scenarios
4043 4034 * such as Fabric topology, the fc_remote_port_t is already created
4044 4035 * and initialized with appropriate values (as the NS provides
4045 4036 * them)
4046 4037 */
4047 4038 static int
4048 4039 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
4049 4040 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
4050 4041 {
4051 4042 uchar_t class;
4052 4043 fp_cmd_t *cmd;
4053 4044 uint32_t src_id;
4054 4045 fc_remote_port_t *tmp_pd;
4055 4046 int relogin;
4056 4047 int found = 0;
4057 4048
4058 4049 #ifdef DEBUG
4059 4050 if (pd == NULL) {
4060 4051 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
4061 4052 }
4062 4053 #endif
4063 4054 ASSERT(job->job_counter > 0);
4064 4055
4065 4056 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4066 4057 if (class == FC_TRAN_CLASS_INVALID) {
4067 4058 return (FC_ELS_BAD);
4068 4059 }
4069 4060
4070 4061 mutex_enter(&port->fp_mutex);
4071 4062 tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4072 4063 mutex_exit(&port->fp_mutex);
4073 4064
4074 4065 relogin = 1;
4075 4066 if (tmp_pd) {
4076 4067 mutex_enter(&tmp_pd->pd_mutex);
4077 4068 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4078 4069 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4079 4070 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4080 4071 relogin = 0;
4081 4072 }
4082 4073 mutex_exit(&tmp_pd->pd_mutex);
4083 4074 }
4084 4075
4085 4076 if (!relogin) {
4086 4077 mutex_enter(&tmp_pd->pd_mutex);
4087 4078 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4088 4079 cmd_flag |= FP_CMD_PLOGI_RETAIN;
4089 4080 }
4090 4081 mutex_exit(&tmp_pd->pd_mutex);
4091 4082
4092 4083 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4093 4084 sizeof (la_els_adisc_t), sleep, tmp_pd);
4094 4085 if (cmd == NULL) {
4095 4086 return (FC_NOMEM);
4096 4087 }
4097 4088
4098 4089 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4099 4090 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4100 4091 cmd->cmd_flags = cmd_flag;
4101 4092 cmd->cmd_retry_count = fp_retry_count;
4102 4093 cmd->cmd_ulp_pkt = ulp_pkt;
4103 4094
4104 4095 mutex_enter(&port->fp_mutex);
4105 4096 mutex_enter(&tmp_pd->pd_mutex);
4106 4097 fp_adisc_init(cmd, job);
4107 4098 mutex_exit(&tmp_pd->pd_mutex);
4108 4099 mutex_exit(&port->fp_mutex);
4109 4100
4110 4101 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4111 4102 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4112 4103
4113 4104 } else {
4114 4105 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4115 4106 sizeof (la_els_logi_t), sleep, pd);
4116 4107 if (cmd == NULL) {
4117 4108 return (FC_NOMEM);
4118 4109 }
4119 4110
4120 4111 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4121 4112 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4122 4113 cmd->cmd_flags = cmd_flag;
4123 4114 cmd->cmd_retry_count = fp_retry_count;
4124 4115 cmd->cmd_ulp_pkt = ulp_pkt;
4125 4116
4126 4117 mutex_enter(&port->fp_mutex);
4127 4118 src_id = port->fp_port_id.port_id;
4128 4119 mutex_exit(&port->fp_mutex);
4129 4120
4130 4121 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4131 4122 job, LA_ELS_PLOGI);
4132 4123 }
4133 4124
4134 4125 if (pd) {
4135 4126 mutex_enter(&pd->pd_mutex);
4136 4127 pd->pd_flags = PD_ELS_IN_PROGRESS;
4137 4128 mutex_exit(&pd->pd_mutex);
4138 4129 }
4139 4130
4140 4131 /* npiv check to make sure we don't log into ourself */
4141 4132 if (relogin &&
4142 4133 ((port->fp_npiv_type == FC_NPIV_PORT) ||
4143 4134 (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
4144 4135 if ((d_id & 0xffff00) ==
4145 4136 (port->fp_port_id.port_id & 0xffff00)) {
4146 4137 found = 1;
4147 4138 }
4148 4139 }
4149 4140
4150 4141 if (found ||
4151 4142 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4152 4143 if (found) {
4153 4144 fc_packet_t *pkt = &cmd->cmd_pkt;
4154 4145 pkt->pkt_state = FC_PKT_NPORT_RJT;
4155 4146 }
4156 4147 if (pd) {
4157 4148 mutex_enter(&pd->pd_mutex);
4158 4149 pd->pd_flags = PD_IDLE;
4159 4150 mutex_exit(&pd->pd_mutex);
4160 4151 }
4161 4152
4162 4153 if (ulp_pkt) {
4163 4154 fc_packet_t *pkt = &cmd->cmd_pkt;
4164 4155
4165 4156 ulp_pkt->pkt_state = pkt->pkt_state;
4166 4157 ulp_pkt->pkt_reason = pkt->pkt_reason;
4167 4158 ulp_pkt->pkt_action = pkt->pkt_action;
4168 4159 ulp_pkt->pkt_expln = pkt->pkt_expln;
4169 4160 }
4170 4161
4171 4162 fp_iodone(cmd);
4172 4163 }
4173 4164
4174 4165 return (FC_SUCCESS);
4175 4166 }
4176 4167
4177 4168
4178 4169 /*
4179 4170 * Register the LOGIN parameters with a port device
4180 4171 */
4181 4172 static void
4182 4173 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4183 4174 la_els_logi_t *acc, uchar_t class)
4184 4175 {
4185 4176 fc_remote_node_t *node;
4186 4177
4187 4178 ASSERT(pd != NULL);
4188 4179
4189 4180 mutex_enter(&pd->pd_mutex);
4190 4181 node = pd->pd_remote_nodep;
4191 4182 if (pd->pd_login_count == 0) {
4192 4183 pd->pd_login_count++;
4193 4184 }
4194 4185
4195 4186 if (handle) {
4196 4187 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
4197 4188 (uint8_t *)&acc->common_service,
4198 4189 sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4199 4190 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
4200 4191 (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4201 4192 DDI_DEV_AUTOINCR);
4202 4193 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
4203 4194 (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4204 4195 DDI_DEV_AUTOINCR);
4205 4196 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
4206 4197 (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4207 4198 DDI_DEV_AUTOINCR);
4208 4199 } else {
↓ open down ↓ |
1737 lines elided |
↑ open up ↑ |
4209 4200 pd->pd_csp = acc->common_service;
4210 4201 pd->pd_clsp1 = acc->class_1;
4211 4202 pd->pd_clsp2 = acc->class_2;
4212 4203 pd->pd_clsp3 = acc->class_3;
4213 4204 }
4214 4205
4215 4206 pd->pd_state = PORT_DEVICE_LOGGED_IN;
4216 4207 pd->pd_login_class = class;
4217 4208 mutex_exit(&pd->pd_mutex);
4218 4209
4219 -#ifndef __lock_lint
4220 4210 ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4221 4211 pd->pd_port_id.port_id) == pd);
4222 -#endif
4223 4212
4224 4213 mutex_enter(&node->fd_mutex);
4225 4214 if (handle) {
4226 4215 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
4227 4216 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4228 4217 DDI_DEV_AUTOINCR);
4229 4218 } else {
4230 4219 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4231 4220 }
4232 4221 mutex_exit(&node->fd_mutex);
4233 4222 }
4234 4223
4235 4224
4236 4225 /*
4237 4226 * Mark the remote port as OFFLINE
4238 4227 */
4239 4228 static void
4240 4229 fp_remote_port_offline(fc_remote_port_t *pd)
4241 4230 {
4242 4231 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4243 4232 if (pd->pd_login_count &&
4244 4233 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4245 4234 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4246 4235 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4247 4236 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4248 4237 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4249 4238 pd->pd_login_class = 0;
4250 4239 }
4251 4240 pd->pd_type = PORT_DEVICE_OLD;
4252 4241 pd->pd_flags = PD_IDLE;
4253 4242 fctl_tc_reset(&pd->pd_logo_tc);
4254 4243 }
4255 4244
4256 4245
4257 4246 /*
4258 4247 * Deregistration of a port device
4259 4248 */
4260 4249 static void
4261 4250 fp_unregister_login(fc_remote_port_t *pd)
4262 4251 {
4263 4252 fc_remote_node_t *node;
4264 4253
4265 4254 ASSERT(pd != NULL);
4266 4255
4267 4256 mutex_enter(&pd->pd_mutex);
4268 4257 pd->pd_login_count = 0;
4269 4258 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4270 4259 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4271 4260 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4272 4261 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4273 4262
4274 4263 pd->pd_state = PORT_DEVICE_VALID;
4275 4264 pd->pd_login_class = 0;
4276 4265 node = pd->pd_remote_nodep;
4277 4266 mutex_exit(&pd->pd_mutex);
4278 4267
4279 4268 mutex_enter(&node->fd_mutex);
4280 4269 bzero(node->fd_vv, sizeof (node->fd_vv));
4281 4270 mutex_exit(&node->fd_mutex);
4282 4271 }
4283 4272
4284 4273
4285 4274 /*
4286 4275 * Handle OFFLINE state of an FCA port
4287 4276 */
4288 4277 static void
4289 4278 fp_port_offline(fc_local_port_t *port, int notify)
4290 4279 {
4291 4280 int index;
4292 4281 int statec;
4293 4282 timeout_id_t tid;
4294 4283 struct pwwn_hash *head;
4295 4284 fc_remote_port_t *pd;
4296 4285
4297 4286 ASSERT(MUTEX_HELD(&port->fp_mutex));
4298 4287
4299 4288 for (index = 0; index < pwwn_table_size; index++) {
4300 4289 head = &port->fp_pwwn_table[index];
4301 4290 pd = head->pwwn_head;
4302 4291 while (pd != NULL) {
4303 4292 mutex_enter(&pd->pd_mutex);
4304 4293 fp_remote_port_offline(pd);
4305 4294 fctl_delist_did_table(port, pd);
4306 4295 mutex_exit(&pd->pd_mutex);
4307 4296 pd = pd->pd_wwn_hnext;
4308 4297 }
4309 4298 }
4310 4299 port->fp_total_devices = 0;
4311 4300
4312 4301 statec = 0;
4313 4302 if (notify) {
4314 4303 /*
4315 4304 * Decrement the statec busy counter as we
4316 4305 * are almost done with handling the state
4317 4306 * change
4318 4307 */
4319 4308 ASSERT(port->fp_statec_busy > 0);
4320 4309 if (--port->fp_statec_busy == 0) {
4321 4310 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4322 4311 }
4323 4312 mutex_exit(&port->fp_mutex);
4324 4313 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4325 4314 0, 0, KM_SLEEP);
4326 4315 mutex_enter(&port->fp_mutex);
4327 4316
4328 4317 if (port->fp_statec_busy) {
4329 4318 statec++;
4330 4319 }
4331 4320 } else if (port->fp_statec_busy > 1) {
4332 4321 statec++;
4333 4322 }
4334 4323
4335 4324 if ((tid = port->fp_offline_tid) != NULL) {
4336 4325 mutex_exit(&port->fp_mutex);
4337 4326 (void) untimeout(tid);
4338 4327 mutex_enter(&port->fp_mutex);
4339 4328 }
4340 4329
4341 4330 if (!statec) {
4342 4331 port->fp_offline_tid = timeout(fp_offline_timeout,
4343 4332 (caddr_t)port, fp_offline_ticks);
4344 4333 }
4345 4334 }
4346 4335
4347 4336
4348 4337 /*
4349 4338 * Offline devices and send up a state change notification to ULPs
4350 4339 */
4351 4340 static void
4352 4341 fp_offline_timeout(void *port_handle)
4353 4342 {
4354 4343 int ret;
4355 4344 fc_local_port_t *port = port_handle;
4356 4345 uint32_t listlen = 0;
4357 4346 fc_portmap_t *changelist = NULL;
4358 4347
4359 4348 mutex_enter(&port->fp_mutex);
4360 4349
4361 4350 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4362 4351 (port->fp_soft_state &
4363 4352 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4364 4353 port->fp_dev_count == 0 || port->fp_statec_busy) {
4365 4354 port->fp_offline_tid = NULL;
4366 4355 mutex_exit(&port->fp_mutex);
4367 4356 return;
4368 4357 }
4369 4358
4370 4359 mutex_exit(&port->fp_mutex);
4371 4360
4372 4361 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4373 4362
4374 4363 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4375 4364 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4376 4365 FC_FCA_CORE)) != FC_SUCCESS) {
4377 4366 FP_TRACE(FP_NHEAD1(9, ret),
4378 4367 "Failed to force adapter dump");
4379 4368 } else {
4380 4369 FP_TRACE(FP_NHEAD1(9, 0),
4381 4370 "Forced adapter dump successfully");
4382 4371 }
4383 4372 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4384 4373 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4385 4374 FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4386 4375 FP_TRACE(FP_NHEAD1(9, ret),
4387 4376 "Failed to force adapter dump and reset");
4388 4377 } else {
4389 4378 FP_TRACE(FP_NHEAD1(9, 0),
4390 4379 "Forced adapter dump and reset successfully");
4391 4380 }
4392 4381 }
4393 4382
4394 4383 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4395 4384 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4396 4385 listlen, listlen, KM_SLEEP);
4397 4386
4398 4387 mutex_enter(&port->fp_mutex);
4399 4388 port->fp_offline_tid = NULL;
4400 4389 mutex_exit(&port->fp_mutex);
4401 4390 }
4402 4391
4403 4392
4404 4393 /*
4405 4394 * Perform general purpose ELS request initialization
4406 4395 */
4407 4396 static void
4408 4397 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4409 4398 void (*comp) (), job_request_t *job)
4410 4399 {
4411 4400 fc_packet_t *pkt;
4412 4401
4413 4402 pkt = &cmd->cmd_pkt;
4414 4403 cmd->cmd_job = job;
4415 4404
4416 4405 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4417 4406 pkt->pkt_cmd_fhdr.d_id = d_id;
4418 4407 pkt->pkt_cmd_fhdr.s_id = s_id;
4419 4408 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4420 4409 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4421 4410 pkt->pkt_cmd_fhdr.seq_id = 0;
4422 4411 pkt->pkt_cmd_fhdr.df_ctl = 0;
4423 4412 pkt->pkt_cmd_fhdr.seq_cnt = 0;
4424 4413 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4425 4414 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4426 4415 pkt->pkt_cmd_fhdr.ro = 0;
4427 4416 pkt->pkt_cmd_fhdr.rsvd = 0;
4428 4417 pkt->pkt_comp = comp;
4429 4418 pkt->pkt_timeout = FP_ELS_TIMEOUT;
4430 4419 }
4431 4420
4432 4421
4433 4422 /*
4434 4423 * Initialize PLOGI/FLOGI ELS request
4435 4424 */
4436 4425 static void
4437 4426 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4438 4427 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4439 4428 {
4440 4429 ls_code_t payload;
4441 4430
4442 4431 fp_els_init(cmd, s_id, d_id, intr, job);
4443 4432 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4444 4433
4445 4434 payload.ls_code = ls_code;
4446 4435 payload.mbz = 0;
4447 4436
4448 4437 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
4449 4438 (uint8_t *)&port->fp_service_params,
4450 4439 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4451 4440 DDI_DEV_AUTOINCR);
4452 4441
4453 4442 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4454 4443 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4455 4444 DDI_DEV_AUTOINCR);
4456 4445 }
4457 4446
4458 4447
4459 4448 /*
4460 4449 * Initialize LOGO ELS request
4461 4450 */
4462 4451 static void
4463 4452 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4464 4453 {
4465 4454 fc_local_port_t *port;
4466 4455 fc_packet_t *pkt;
4467 4456 la_els_logo_t payload;
4468 4457
4469 4458 port = pd->pd_port;
4470 4459 pkt = &cmd->cmd_pkt;
4471 4460 ASSERT(MUTEX_HELD(&port->fp_mutex));
4472 4461 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4473 4462
4474 4463 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4475 4464 fp_logo_intr, job);
4476 4465
4477 4466 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4478 4467
4479 4468 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4480 4469 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4481 4470
4482 4471 payload.ls_code.ls_code = LA_ELS_LOGO;
4483 4472 payload.ls_code.mbz = 0;
4484 4473 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4485 4474 payload.nport_id = port->fp_port_id;
4486 4475
4487 4476 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4488 4477 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4489 4478 }
4490 4479
4491 4480 /*
4492 4481 * Initialize RNID ELS request
4493 4482 */
4494 4483 static void
4495 4484 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4496 4485 {
4497 4486 fc_local_port_t *port;
4498 4487 fc_packet_t *pkt;
4499 4488 la_els_rnid_t payload;
4500 4489 fc_remote_port_t *pd;
4501 4490
4502 4491 pkt = &cmd->cmd_pkt;
4503 4492 pd = pkt->pkt_pd;
4504 4493 port = pd->pd_port;
4505 4494
4506 4495 ASSERT(MUTEX_HELD(&port->fp_mutex));
4507 4496 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4508 4497
4509 4498 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4510 4499 fp_rnid_intr, job);
4511 4500
4512 4501 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4513 4502 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4514 4503 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4515 4504
4516 4505 payload.ls_code.ls_code = LA_ELS_RNID;
4517 4506 payload.ls_code.mbz = 0;
4518 4507 payload.data_format = flag;
4519 4508
4520 4509 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4521 4510 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4522 4511 }
4523 4512
4524 4513 /*
4525 4514 * Initialize RLS ELS request
4526 4515 */
4527 4516 static void
4528 4517 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4529 4518 {
4530 4519 fc_local_port_t *port;
4531 4520 fc_packet_t *pkt;
4532 4521 la_els_rls_t payload;
4533 4522 fc_remote_port_t *pd;
4534 4523
4535 4524 pkt = &cmd->cmd_pkt;
4536 4525 pd = pkt->pkt_pd;
4537 4526 port = pd->pd_port;
4538 4527
4539 4528 ASSERT(MUTEX_HELD(&port->fp_mutex));
4540 4529 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4541 4530
4542 4531 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4543 4532 fp_rls_intr, job);
4544 4533
4545 4534 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4546 4535 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4547 4536 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4548 4537
4549 4538 payload.ls_code.ls_code = LA_ELS_RLS;
4550 4539 payload.ls_code.mbz = 0;
4551 4540 payload.rls_portid = port->fp_port_id;
4552 4541
4553 4542 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4554 4543 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4555 4544 }
4556 4545
4557 4546
4558 4547 /*
4559 4548 * Initialize an ADISC ELS request
4560 4549 */
4561 4550 static void
4562 4551 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4563 4552 {
4564 4553 fc_local_port_t *port;
4565 4554 fc_packet_t *pkt;
4566 4555 la_els_adisc_t payload;
4567 4556 fc_remote_port_t *pd;
4568 4557
4569 4558 pkt = &cmd->cmd_pkt;
4570 4559 pd = pkt->pkt_pd;
4571 4560 port = pd->pd_port;
4572 4561
4573 4562 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4574 4563 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4575 4564
4576 4565 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4577 4566 fp_adisc_intr, job);
4578 4567
4579 4568 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4580 4569 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4581 4570 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4582 4571
4583 4572 payload.ls_code.ls_code = LA_ELS_ADISC;
4584 4573 payload.ls_code.mbz = 0;
4585 4574 payload.nport_id = port->fp_port_id;
4586 4575 payload.port_wwn = port->fp_service_params.nport_ww_name;
4587 4576 payload.node_wwn = port->fp_service_params.node_ww_name;
4588 4577 payload.hard_addr = port->fp_hard_addr;
4589 4578
4590 4579 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4591 4580 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4592 4581 }
4593 4582
4594 4583
4595 4584 /*
4596 4585 * Send up a state change notification to ULPs.
4597 4586 * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4598 4587 */
4599 4588 static int
4600 4589 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4601 4590 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4602 4591 {
4603 4592 fc_port_clist_t *clist;
4604 4593 fc_remote_port_t *pd;
4605 4594 int count;
4606 4595
4607 4596 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4608 4597
4609 4598 clist = kmem_zalloc(sizeof (*clist), sleep);
4610 4599 if (clist == NULL) {
4611 4600 kmem_free(changelist, alloc_len * sizeof (*changelist));
4612 4601 return (FC_NOMEM);
4613 4602 }
4614 4603
4615 4604 clist->clist_state = state;
4616 4605
4617 4606 mutex_enter(&port->fp_mutex);
4618 4607 clist->clist_flags = port->fp_topology;
4619 4608 mutex_exit(&port->fp_mutex);
4620 4609
4621 4610 clist->clist_port = (opaque_t)port;
4622 4611 clist->clist_len = listlen;
4623 4612 clist->clist_size = alloc_len;
4624 4613 clist->clist_map = changelist;
4625 4614
4626 4615 /*
4627 4616 * Bump the reference count of each fc_remote_port_t in this changelist.
4628 4617 * This is necessary since these devices will be sitting in a taskq
4629 4618 * and referenced later. When the state change notification is
4630 4619 * complete, the reference counts will be decremented.
4631 4620 */
4632 4621 for (count = 0; count < clist->clist_len; count++) {
4633 4622 pd = clist->clist_map[count].map_pd;
4634 4623
4635 4624 if (pd != NULL) {
4636 4625 mutex_enter(&pd->pd_mutex);
4637 4626 ASSERT((pd->pd_ref_count >= 0) ||
4638 4627 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4639 4628 pd->pd_ref_count++;
4640 4629
4641 4630 if (clist->clist_map[count].map_state !=
4642 4631 PORT_DEVICE_INVALID) {
4643 4632 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4644 4633 }
4645 4634
4646 4635 mutex_exit(&pd->pd_mutex);
4647 4636 }
4648 4637 }
4649 4638
4650 4639 #ifdef DEBUG
4651 4640 /*
4652 4641 * Sanity check for presence of OLD devices in the hash lists
4653 4642 */
4654 4643 if (clist->clist_size) {
4655 4644 ASSERT(clist->clist_map != NULL);
4656 4645 for (count = 0; count < clist->clist_len; count++) {
4657 4646 if (clist->clist_map[count].map_state ==
4658 4647 PORT_DEVICE_INVALID) {
4659 4648 la_wwn_t pwwn;
4660 4649 fc_portid_t d_id;
4661 4650
4662 4651 pd = clist->clist_map[count].map_pd;
4663 4652 ASSERT(pd != NULL);
4664 4653
4665 4654 mutex_enter(&pd->pd_mutex);
4666 4655 pwwn = pd->pd_port_name;
4667 4656 d_id = pd->pd_port_id;
4668 4657 mutex_exit(&pd->pd_mutex);
4669 4658
4670 4659 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4671 4660 ASSERT(pd != clist->clist_map[count].map_pd);
4672 4661
4673 4662 pd = fctl_get_remote_port_by_did(port,
4674 4663 d_id.port_id);
4675 4664 ASSERT(pd != clist->clist_map[count].map_pd);
4676 4665 }
4677 4666 }
4678 4667 }
4679 4668 #endif
4680 4669
4681 4670 mutex_enter(&port->fp_mutex);
4682 4671
4683 4672 if (state == FC_STATE_ONLINE) {
4684 4673 if (--port->fp_statec_busy == 0) {
4685 4674 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4686 4675 }
4687 4676 }
4688 4677 mutex_exit(&port->fp_mutex);
4689 4678
4690 4679 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4691 4680 clist, KM_SLEEP);
4692 4681
4693 4682 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4694 4683 "state=%x, len=%d", port, state, listlen);
4695 4684
4696 4685 return (FC_SUCCESS);
4697 4686 }
4698 4687
4699 4688
4700 4689 /*
4701 4690 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4702 4691 */
4703 4692 static int
4704 4693 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4705 4694 uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4706 4695 {
4707 4696 int ret;
4708 4697 fc_port_clist_t *clist;
4709 4698
4710 4699 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4711 4700
4712 4701 clist = kmem_zalloc(sizeof (*clist), sleep);
4713 4702 if (clist == NULL) {
4714 4703 kmem_free(changelist, alloc_len * sizeof (*changelist));
4715 4704 return (FC_NOMEM);
4716 4705 }
4717 4706
4718 4707 clist->clist_state = FC_STATE_DEVICE_CHANGE;
4719 4708
4720 4709 mutex_enter(&port->fp_mutex);
4721 4710 clist->clist_flags = port->fp_topology;
4722 4711 mutex_exit(&port->fp_mutex);
4723 4712
4724 4713 clist->clist_port = (opaque_t)port;
4725 4714 clist->clist_len = listlen;
4726 4715 clist->clist_size = alloc_len;
4727 4716 clist->clist_map = changelist;
4728 4717
4729 4718 /* Send sysevents for target state changes */
4730 4719
4731 4720 if (clist->clist_size) {
4732 4721 int count;
4733 4722 fc_remote_port_t *pd;
4734 4723
4735 4724 ASSERT(clist->clist_map != NULL);
4736 4725 for (count = 0; count < clist->clist_len; count++) {
4737 4726 pd = clist->clist_map[count].map_pd;
4738 4727
4739 4728 /*
4740 4729 * Bump reference counts on all fc_remote_port_t
4741 4730 * structs in this list. We don't know when the task
4742 4731 * will fire, and we don't need these fc_remote_port_t
4743 4732 * structs going away behind our back.
4744 4733 */
4745 4734 if (pd) {
4746 4735 mutex_enter(&pd->pd_mutex);
4747 4736 ASSERT((pd->pd_ref_count >= 0) ||
4748 4737 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4749 4738 pd->pd_ref_count++;
4750 4739 mutex_exit(&pd->pd_mutex);
4751 4740 }
4752 4741
4753 4742 if (clist->clist_map[count].map_state ==
4754 4743 PORT_DEVICE_VALID) {
4755 4744 if (clist->clist_map[count].map_type ==
4756 4745 PORT_DEVICE_NEW) {
4757 4746 /* Update our state change counter */
4758 4747 mutex_enter(&port->fp_mutex);
4759 4748 port->fp_last_change++;
4760 4749 mutex_exit(&port->fp_mutex);
4761 4750
4762 4751 /* Additions */
4763 4752 fp_log_target_event(port,
4764 4753 ESC_SUNFC_TARGET_ADD,
4765 4754 clist->clist_map[count].map_pwwn,
4766 4755 clist->clist_map[count].map_did.
4767 4756 port_id);
4768 4757 }
4769 4758
4770 4759 } else if ((clist->clist_map[count].map_type ==
4771 4760 PORT_DEVICE_OLD) &&
4772 4761 (clist->clist_map[count].map_state ==
4773 4762 PORT_DEVICE_INVALID)) {
4774 4763 /* Update our state change counter */
4775 4764 mutex_enter(&port->fp_mutex);
4776 4765 port->fp_last_change++;
4777 4766 mutex_exit(&port->fp_mutex);
4778 4767
4779 4768 /*
4780 4769 * For removals, we don't decrement
4781 4770 * pd_ref_count until after the ULP's
4782 4771 * state change callback function has
4783 4772 * completed.
4784 4773 */
4785 4774
4786 4775 /* Removals */
4787 4776 fp_log_target_event(port,
4788 4777 ESC_SUNFC_TARGET_REMOVE,
4789 4778 clist->clist_map[count].map_pwwn,
4790 4779 clist->clist_map[count].map_did.port_id);
4791 4780 }
4792 4781
4793 4782 if (clist->clist_map[count].map_state !=
4794 4783 PORT_DEVICE_INVALID) {
4795 4784 /*
4796 4785 * Indicate that the ULPs are now aware of
4797 4786 * this device.
4798 4787 */
4799 4788
4800 4789 mutex_enter(&pd->pd_mutex);
4801 4790 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4802 4791 mutex_exit(&pd->pd_mutex);
4803 4792 }
4804 4793
4805 4794 #ifdef DEBUG
4806 4795 /*
4807 4796 * Sanity check for OLD devices in the hash lists
4808 4797 */
4809 4798 if (pd && clist->clist_map[count].map_state ==
4810 4799 PORT_DEVICE_INVALID) {
4811 4800 la_wwn_t pwwn;
4812 4801 fc_portid_t d_id;
4813 4802
4814 4803 mutex_enter(&pd->pd_mutex);
4815 4804 pwwn = pd->pd_port_name;
4816 4805 d_id = pd->pd_port_id;
4817 4806 mutex_exit(&pd->pd_mutex);
4818 4807
4819 4808 /*
4820 4809 * This overwrites the 'pd' local variable.
4821 4810 * Beware of this if 'pd' ever gets
4822 4811 * referenced below this block.
4823 4812 */
4824 4813 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4825 4814 ASSERT(pd != clist->clist_map[count].map_pd);
4826 4815
4827 4816 pd = fctl_get_remote_port_by_did(port,
4828 4817 d_id.port_id);
4829 4818 ASSERT(pd != clist->clist_map[count].map_pd);
4830 4819 }
4831 4820 #endif
4832 4821 }
4833 4822 }
4834 4823
4835 4824 if (sync) {
4836 4825 clist->clist_wait = 1;
4837 4826 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4838 4827 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4839 4828 }
4840 4829
4841 4830 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4842 4831 if (sync && ret) {
4843 4832 mutex_enter(&clist->clist_mutex);
4844 4833 while (clist->clist_wait) {
4845 4834 cv_wait(&clist->clist_cv, &clist->clist_mutex);
4846 4835 }
4847 4836 mutex_exit(&clist->clist_mutex);
4848 4837
4849 4838 mutex_destroy(&clist->clist_mutex);
4850 4839 cv_destroy(&clist->clist_cv);
4851 4840 kmem_free(clist, sizeof (*clist));
4852 4841 }
4853 4842
4854 4843 if (!ret) {
4855 4844 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4856 4845 "port=%p", port);
4857 4846 kmem_free(clist->clist_map,
4858 4847 sizeof (*(clist->clist_map)) * clist->clist_size);
4859 4848 kmem_free(clist, sizeof (*clist));
4860 4849 } else {
4861 4850 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4862 4851 port, listlen);
4863 4852 }
4864 4853
4865 4854 return (FC_SUCCESS);
4866 4855 }
4867 4856
4868 4857
4869 4858 /*
4870 4859 * Perform PLOGI to the group of devices for ULPs
4871 4860 */
4872 4861 static void
4873 4862 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4874 4863 {
4875 4864 int offline;
4876 4865 int count;
4877 4866 int rval;
4878 4867 uint32_t listlen;
4879 4868 uint32_t done;
4880 4869 uint32_t d_id;
4881 4870 fc_remote_node_t *node;
4882 4871 fc_remote_port_t *pd;
4883 4872 fc_remote_port_t *tmp_pd;
4884 4873 fc_packet_t *ulp_pkt;
4885 4874 la_els_logi_t *els_data;
4886 4875 ls_code_t ls_code;
4887 4876
4888 4877 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4889 4878 port, job);
4890 4879
4891 4880 done = 0;
4892 4881 listlen = job->job_ulp_listlen;
4893 4882 job->job_counter = job->job_ulp_listlen;
4894 4883
4895 4884 mutex_enter(&port->fp_mutex);
4896 4885 offline = (port->fp_statec_busy ||
4897 4886 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4898 4887 mutex_exit(&port->fp_mutex);
4899 4888
4900 4889 for (count = 0; count < listlen; count++) {
4901 4890 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4902 4891 sizeof (la_els_logi_t));
4903 4892
4904 4893 ulp_pkt = job->job_ulp_pkts[count];
4905 4894 pd = ulp_pkt->pkt_pd;
4906 4895 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4907 4896
4908 4897 if (offline) {
4909 4898 done++;
4910 4899
4911 4900 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4912 4901 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4913 4902 ulp_pkt->pkt_pd = NULL;
4914 4903 ulp_pkt->pkt_comp(ulp_pkt);
4915 4904
4916 4905 job->job_ulp_pkts[count] = NULL;
4917 4906
4918 4907 fp_jobdone(job);
4919 4908 continue;
4920 4909 }
4921 4910
4922 4911 if (pd == NULL) {
4923 4912 pd = fctl_get_remote_port_by_did(port, d_id);
4924 4913 if (pd == NULL) {
4925 4914 /* reset later */
4926 4915 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4927 4916 continue;
4928 4917 }
4929 4918 mutex_enter(&pd->pd_mutex);
4930 4919 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4931 4920 mutex_exit(&pd->pd_mutex);
4932 4921 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4933 4922 done++;
4934 4923 ulp_pkt->pkt_comp(ulp_pkt);
4935 4924 job->job_ulp_pkts[count] = NULL;
4936 4925 fp_jobdone(job);
4937 4926 } else {
4938 4927 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4939 4928 mutex_exit(&pd->pd_mutex);
4940 4929 }
4941 4930 continue;
4942 4931 }
4943 4932
4944 4933 switch (ulp_pkt->pkt_state) {
4945 4934 case FC_PKT_ELS_IN_PROGRESS:
4946 4935 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4947 4936 /* FALLTHRU */
4948 4937 case FC_PKT_LOCAL_RJT:
4949 4938 done++;
4950 4939 ulp_pkt->pkt_comp(ulp_pkt);
4951 4940 job->job_ulp_pkts[count] = NULL;
4952 4941 fp_jobdone(job);
4953 4942 continue;
4954 4943 default:
4955 4944 break;
4956 4945 }
4957 4946
4958 4947 /*
4959 4948 * Validate the pd corresponding to the d_id passed
4960 4949 * by the ULPs
4961 4950 */
4962 4951 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4963 4952 if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4964 4953 done++;
4965 4954 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4966 4955 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4967 4956 ulp_pkt->pkt_pd = NULL;
4968 4957 ulp_pkt->pkt_comp(ulp_pkt);
4969 4958 job->job_ulp_pkts[count] = NULL;
4970 4959 fp_jobdone(job);
4971 4960 continue;
4972 4961 }
4973 4962
4974 4963 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4975 4964 "port=%p, pd=%p", port, pd);
4976 4965
4977 4966 mutex_enter(&pd->pd_mutex);
4978 4967
4979 4968 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4980 4969 done++;
4981 4970 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4982 4971
4983 4972 ls_code.ls_code = LA_ELS_ACC;
4984 4973 ls_code.mbz = 0;
4985 4974
4986 4975 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4987 4976 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4988 4977 sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4989 4978
4990 4979 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4991 4980 (uint8_t *)&pd->pd_csp,
4992 4981 (uint8_t *)&els_data->common_service,
4993 4982 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4994 4983
4995 4984 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4996 4985 (uint8_t *)&pd->pd_port_name,
4997 4986 (uint8_t *)&els_data->nport_ww_name,
4998 4987 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
4999 4988
5000 4989 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5001 4990 (uint8_t *)&pd->pd_clsp1,
5002 4991 (uint8_t *)&els_data->class_1,
5003 4992 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
5004 4993
5005 4994 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5006 4995 (uint8_t *)&pd->pd_clsp2,
5007 4996 (uint8_t *)&els_data->class_2,
5008 4997 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
5009 4998
5010 4999 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5011 5000 (uint8_t *)&pd->pd_clsp3,
5012 5001 (uint8_t *)&els_data->class_3,
5013 5002 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
5014 5003
5015 5004 node = pd->pd_remote_nodep;
5016 5005 pd->pd_login_count++;
5017 5006 pd->pd_flags = PD_IDLE;
5018 5007 ulp_pkt->pkt_pd = pd;
5019 5008 mutex_exit(&pd->pd_mutex);
5020 5009
5021 5010 mutex_enter(&node->fd_mutex);
5022 5011 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5023 5012 (uint8_t *)&node->fd_node_name,
5024 5013 (uint8_t *)(&els_data->node_ww_name),
5025 5014 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
5026 5015
5027 5016 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5028 5017 (uint8_t *)&node->fd_vv,
5029 5018 (uint8_t *)(&els_data->vendor_version),
5030 5019 sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
5031 5020
5032 5021 mutex_exit(&node->fd_mutex);
5033 5022 ulp_pkt->pkt_state = FC_PKT_SUCCESS;
5034 5023 } else {
5035 5024
5036 5025 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
5037 5026 mutex_exit(&pd->pd_mutex);
5038 5027 }
5039 5028
5040 5029 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
5041 5030 ulp_pkt->pkt_comp(ulp_pkt);
5042 5031 job->job_ulp_pkts[count] = NULL;
5043 5032 fp_jobdone(job);
5044 5033 }
5045 5034 }
5046 5035
5047 5036 if (done == listlen) {
5048 5037 fp_jobwait(job);
5049 5038 fctl_jobdone(job);
5050 5039 return;
5051 5040 }
5052 5041
5053 5042 job->job_counter = listlen - done;
5054 5043
5055 5044 for (count = 0; count < listlen; count++) {
5056 5045 int cmd_flags;
5057 5046
5058 5047 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
5059 5048 continue;
5060 5049 }
5061 5050
5062 5051 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
5063 5052
5064 5053 cmd_flags = FP_CMD_PLOGI_RETAIN;
5065 5054
5066 5055 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5067 5056 ASSERT(d_id != 0);
5068 5057
5069 5058 pd = fctl_get_remote_port_by_did(port, d_id);
5070 5059
5071 5060 /*
5072 5061 * We need to properly adjust the port device
5073 5062 * reference counter before we assign the pd
5074 5063 * to the ULP packets port device pointer.
5075 5064 */
5076 5065 if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
5077 5066 mutex_enter(&pd->pd_mutex);
5078 5067 pd->pd_ref_count++;
5079 5068 mutex_exit(&pd->pd_mutex);
5080 5069 FP_TRACE(FP_NHEAD1(3, 0),
5081 5070 "fp_plogi_group: DID = 0x%x using new pd %p \
5082 5071 old pd NULL\n", d_id, pd);
5083 5072 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
5084 5073 ulp_pkt->pkt_pd != pd) {
5085 5074 mutex_enter(&pd->pd_mutex);
5086 5075 pd->pd_ref_count++;
5087 5076 mutex_exit(&pd->pd_mutex);
5088 5077 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5089 5078 ulp_pkt->pkt_pd->pd_ref_count--;
5090 5079 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5091 5080 FP_TRACE(FP_NHEAD1(3, 0),
5092 5081 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
5093 5082 d_id, ulp_pkt->pkt_pd, pd);
5094 5083 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
5095 5084 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5096 5085 ulp_pkt->pkt_pd->pd_ref_count--;
5097 5086 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5098 5087 FP_TRACE(FP_NHEAD1(3, 0),
5099 5088 "fp_plogi_group: DID = 0x%x pd is NULL and \
5100 5089 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
5101 5090 }
5102 5091
5103 5092 ulp_pkt->pkt_pd = pd;
5104 5093
5105 5094 if (pd != NULL) {
5106 5095 mutex_enter(&pd->pd_mutex);
5107 5096 d_id = pd->pd_port_id.port_id;
5108 5097 pd->pd_flags = PD_ELS_IN_PROGRESS;
5109 5098 mutex_exit(&pd->pd_mutex);
5110 5099 } else {
5111 5100 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5112 5101 #ifdef DEBUG
5113 5102 pd = fctl_get_remote_port_by_did(port, d_id);
5114 5103 ASSERT(pd == NULL);
5115 5104 #endif
5116 5105 /*
5117 5106 * In the Fabric topology, use NS to create
5118 5107 * port device, and if that fails still try
5119 5108 * with PLOGI - which will make yet another
5120 5109 * attempt to create after successful PLOGI
5121 5110 */
5122 5111 mutex_enter(&port->fp_mutex);
5123 5112 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5124 5113 mutex_exit(&port->fp_mutex);
5125 5114 pd = fp_create_remote_port_by_ns(port,
5126 5115 d_id, KM_SLEEP);
5127 5116 if (pd) {
5128 5117 cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5129 5118
5130 5119 mutex_enter(&pd->pd_mutex);
5131 5120 pd->pd_flags = PD_ELS_IN_PROGRESS;
5132 5121 mutex_exit(&pd->pd_mutex);
5133 5122
5134 5123 FP_TRACE(FP_NHEAD1(3, 0),
5135 5124 "fp_plogi_group;"
5136 5125 " NS created PD port=%p, job=%p,"
5137 5126 " pd=%p", port, job, pd);
5138 5127 }
5139 5128 } else {
5140 5129 mutex_exit(&port->fp_mutex);
5141 5130 }
5142 5131 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5143 5132 FP_TRACE(FP_NHEAD1(3, 0),
5144 5133 "fp_plogi_group;"
5145 5134 "ulp_pkt's pd is NULL, get a pd %p",
5146 5135 pd);
5147 5136 mutex_enter(&pd->pd_mutex);
5148 5137 pd->pd_ref_count++;
5149 5138 mutex_exit(&pd->pd_mutex);
5150 5139 }
5151 5140 ulp_pkt->pkt_pd = pd;
5152 5141 }
5153 5142
5154 5143 rval = fp_port_login(port, d_id, job, cmd_flags,
5155 5144 KM_SLEEP, pd, ulp_pkt);
5156 5145
5157 5146 if (rval == FC_SUCCESS) {
5158 5147 continue;
5159 5148 }
5160 5149
5161 5150 if (rval == FC_STATEC_BUSY) {
5162 5151 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5163 5152 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5164 5153 } else {
5165 5154 ulp_pkt->pkt_state = FC_PKT_FAILURE;
5166 5155 }
5167 5156
5168 5157 if (pd) {
5169 5158 mutex_enter(&pd->pd_mutex);
5170 5159 pd->pd_flags = PD_IDLE;
5171 5160 mutex_exit(&pd->pd_mutex);
5172 5161 }
5173 5162
5174 5163 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5175 5164 ASSERT(pd != NULL);
5176 5165
5177 5166 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5178 5167 " PD removed; port=%p, job=%p", port, job);
5179 5168
5180 5169 mutex_enter(&pd->pd_mutex);
5181 5170 pd->pd_ref_count--;
5182 5171 node = pd->pd_remote_nodep;
5183 5172 mutex_exit(&pd->pd_mutex);
5184 5173
5185 5174 ASSERT(node != NULL);
5186 5175
5187 5176 if (fctl_destroy_remote_port(port, pd) == 0) {
5188 5177 fctl_destroy_remote_node(node);
5189 5178 }
5190 5179 ulp_pkt->pkt_pd = NULL;
5191 5180 }
5192 5181 ulp_pkt->pkt_comp(ulp_pkt);
5193 5182 fp_jobdone(job);
5194 5183 }
5195 5184
5196 5185 fp_jobwait(job);
5197 5186 fctl_jobdone(job);
5198 5187
5199 5188 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5200 5189 port, job);
5201 5190 }
5202 5191
5203 5192
5204 5193 /*
5205 5194 * Name server request initialization
5206 5195 */
5207 5196 static void
5208 5197 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5209 5198 {
5210 5199 int rval;
5211 5200 int count;
5212 5201 int size;
5213 5202
5214 5203 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5215 5204
5216 5205 job->job_counter = 1;
5217 5206 job->job_result = FC_SUCCESS;
5218 5207
5219 5208 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5220 5209 KM_SLEEP, NULL, NULL);
5221 5210
5222 5211 if (rval != FC_SUCCESS) {
5223 5212 mutex_enter(&port->fp_mutex);
5224 5213 port->fp_topology = FC_TOP_NO_NS;
5225 5214 mutex_exit(&port->fp_mutex);
5226 5215 return;
5227 5216 }
5228 5217
5229 5218 fp_jobwait(job);
5230 5219
5231 5220 if (job->job_result != FC_SUCCESS) {
5232 5221 mutex_enter(&port->fp_mutex);
5233 5222 port->fp_topology = FC_TOP_NO_NS;
5234 5223 mutex_exit(&port->fp_mutex);
5235 5224 return;
5236 5225 }
5237 5226
5238 5227 /*
5239 5228 * At this time, we'll do NS registration for objects in the
5240 5229 * ns_reg_cmds (see top of this file) array.
5241 5230 *
5242 5231 * Each time a ULP module registers with the transport, the
5243 5232 * appropriate fc4 bit is set fc4 types and registered with
5244 5233 * the NS for this support. Also, ULPs and FC admin utilities
5245 5234 * may do registration for objects like IP address, symbolic
5246 5235 * port/node name, Initial process associator at run time.
5247 5236 */
5248 5237 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5249 5238 job->job_counter = size;
5250 5239 job->job_result = FC_SUCCESS;
5251 5240
5252 5241 for (count = 0; count < size; count++) {
5253 5242 if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5254 5243 job, 0, sleep) != FC_SUCCESS) {
5255 5244 fp_jobdone(job);
5256 5245 }
5257 5246 }
5258 5247 if (size) {
5259 5248 fp_jobwait(job);
5260 5249 }
5261 5250
5262 5251 job->job_result = FC_SUCCESS;
5263 5252
5264 5253 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5265 5254
5266 5255 if (port->fp_dev_count < FP_MAX_DEVICES) {
5267 5256 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5268 5257 }
5269 5258
5270 5259 job->job_counter = 1;
5271 5260
5272 5261 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5273 5262 sleep) == FC_SUCCESS) {
5274 5263 fp_jobwait(job);
5275 5264 }
5276 5265 }
5277 5266
5278 5267
5279 5268 /*
5280 5269 * Name server finish:
5281 5270 * Unregister for RSCNs
5282 5271 * Unregister all the host port objects in the Name Server
5283 5272 * Perform LOGO with the NS;
5284 5273 */
5285 5274 static void
5286 5275 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5287 5276 {
5288 5277 fp_cmd_t *cmd;
5289 5278 uchar_t class;
5290 5279 uint32_t s_id;
5291 5280 fc_packet_t *pkt;
5292 5281 la_els_logo_t payload;
5293 5282
5294 5283 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5295 5284
5296 5285 job->job_counter = 1;
5297 5286
5298 5287 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5299 5288 FC_SUCCESS) {
5300 5289 fp_jobdone(job);
5301 5290 }
5302 5291 fp_jobwait(job);
5303 5292
5304 5293 job->job_counter = 1;
5305 5294
5306 5295 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5307 5296 fp_jobdone(job);
5308 5297 }
5309 5298 fp_jobwait(job);
5310 5299
5311 5300 job->job_counter = 1;
5312 5301
5313 5302 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5314 5303 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5315 5304 pkt = &cmd->cmd_pkt;
5316 5305
5317 5306 mutex_enter(&port->fp_mutex);
5318 5307 class = port->fp_ns_login_class;
5319 5308 s_id = port->fp_port_id.port_id;
5320 5309 payload.nport_id = port->fp_port_id;
5321 5310 mutex_exit(&port->fp_mutex);
5322 5311
5323 5312 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5324 5313 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5325 5314 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5326 5315 cmd->cmd_retry_count = 1;
5327 5316 cmd->cmd_ulp_pkt = NULL;
5328 5317
5329 5318 if (port->fp_npiv_type == FC_NPIV_PORT) {
5330 5319 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5331 5320 } else {
5332 5321 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5333 5322 }
5334 5323
5335 5324 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5336 5325
5337 5326 payload.ls_code.ls_code = LA_ELS_LOGO;
5338 5327 payload.ls_code.mbz = 0;
5339 5328 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5340 5329
5341 5330 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
5342 5331 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5343 5332
5344 5333 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5345 5334 fp_iodone(cmd);
5346 5335 }
5347 5336 fp_jobwait(job);
5348 5337 }
5349 5338
5350 5339
5351 5340 /*
5352 5341 * NS Registration function.
5353 5342 *
5354 5343 * It should be seriously noted that FC-GS-2 currently doesn't support
5355 5344 * an Object Registration by a D_ID other than the owner of the object.
5356 5345 * What we are aiming at currently is to at least allow Symbolic Node/Port
5357 5346 * Name registration for any N_Port Identifier by the host software.
5358 5347 *
5359 5348 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5360 5349 * function treats the request as Host NS Object.
5361 5350 */
5362 5351 static int
5363 5352 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5364 5353 job_request_t *job, int polled, int sleep)
5365 5354 {
5366 5355 int rval;
5367 5356 fc_portid_t s_id;
5368 5357 fc_packet_t *pkt;
5369 5358 fp_cmd_t *cmd;
5370 5359
5371 5360 if (pd == NULL) {
5372 5361 mutex_enter(&port->fp_mutex);
5373 5362 s_id = port->fp_port_id;
5374 5363 mutex_exit(&port->fp_mutex);
5375 5364 } else {
5376 5365 mutex_enter(&pd->pd_mutex);
5377 5366 s_id = pd->pd_port_id;
5378 5367 mutex_exit(&pd->pd_mutex);
5379 5368 }
5380 5369
5381 5370 if (polled) {
5382 5371 job->job_counter = 1;
5383 5372 }
5384 5373
5385 5374 switch (cmd_code) {
5386 5375 case NS_RPN_ID:
5387 5376 case NS_RNN_ID: {
5388 5377 ns_rxn_req_t rxn;
5389 5378
5390 5379 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5391 5380 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5392 5381 if (cmd == NULL) {
5393 5382 return (FC_NOMEM);
5394 5383 }
5395 5384 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5396 5385 pkt = &cmd->cmd_pkt;
5397 5386
5398 5387 if (pd == NULL) {
5399 5388 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
5400 5389 (port->fp_service_params.nport_ww_name) :
5401 5390 (port->fp_service_params.node_ww_name));
5402 5391 } else {
5403 5392 if (cmd_code == NS_RPN_ID) {
5404 5393 mutex_enter(&pd->pd_mutex);
5405 5394 rxn.rxn_xname = pd->pd_port_name;
5406 5395 mutex_exit(&pd->pd_mutex);
5407 5396 } else {
5408 5397 fc_remote_node_t *node;
5409 5398
5410 5399 mutex_enter(&pd->pd_mutex);
5411 5400 node = pd->pd_remote_nodep;
5412 5401 mutex_exit(&pd->pd_mutex);
5413 5402
5414 5403 mutex_enter(&node->fd_mutex);
5415 5404 rxn.rxn_xname = node->fd_node_name;
5416 5405 mutex_exit(&node->fd_mutex);
5417 5406 }
5418 5407 }
5419 5408 rxn.rxn_port_id = s_id;
5420 5409
5421 5410 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5422 5411 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5423 5412 sizeof (rxn), DDI_DEV_AUTOINCR);
5424 5413
5425 5414 break;
5426 5415 }
5427 5416
5428 5417 case NS_RCS_ID: {
5429 5418 ns_rcos_t rcos;
5430 5419
5431 5420 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5432 5421 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5433 5422 if (cmd == NULL) {
5434 5423 return (FC_NOMEM);
5435 5424 }
5436 5425 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5437 5426 pkt = &cmd->cmd_pkt;
5438 5427
5439 5428 if (pd == NULL) {
5440 5429 rcos.rcos_cos = port->fp_cos;
5441 5430 } else {
5442 5431 mutex_enter(&pd->pd_mutex);
5443 5432 rcos.rcos_cos = pd->pd_cos;
5444 5433 mutex_exit(&pd->pd_mutex);
5445 5434 }
5446 5435 rcos.rcos_port_id = s_id;
5447 5436
5448 5437 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5449 5438 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5450 5439 sizeof (rcos), DDI_DEV_AUTOINCR);
5451 5440
5452 5441 break;
5453 5442 }
5454 5443
5455 5444 case NS_RFT_ID: {
5456 5445 ns_rfc_type_t rfc;
5457 5446
5458 5447 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5459 5448 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5460 5449 NULL);
5461 5450 if (cmd == NULL) {
5462 5451 return (FC_NOMEM);
5463 5452 }
5464 5453 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5465 5454 pkt = &cmd->cmd_pkt;
5466 5455
5467 5456 if (pd == NULL) {
5468 5457 mutex_enter(&port->fp_mutex);
5469 5458 bcopy(port->fp_fc4_types, rfc.rfc_types,
5470 5459 sizeof (port->fp_fc4_types));
5471 5460 mutex_exit(&port->fp_mutex);
5472 5461 } else {
5473 5462 mutex_enter(&pd->pd_mutex);
5474 5463 bcopy(pd->pd_fc4types, rfc.rfc_types,
5475 5464 sizeof (pd->pd_fc4types));
5476 5465 mutex_exit(&pd->pd_mutex);
5477 5466 }
5478 5467 rfc.rfc_port_id = s_id;
5479 5468
5480 5469 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5481 5470 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5482 5471 sizeof (rfc), DDI_DEV_AUTOINCR);
5483 5472
5484 5473 break;
5485 5474 }
5486 5475
5487 5476 case NS_RSPN_ID: {
5488 5477 uchar_t name_len;
5489 5478 int pl_size;
5490 5479 fc_portid_t spn;
5491 5480
5492 5481 if (pd == NULL) {
5493 5482 mutex_enter(&port->fp_mutex);
5494 5483 name_len = port->fp_sym_port_namelen;
5495 5484 mutex_exit(&port->fp_mutex);
5496 5485 } else {
5497 5486 mutex_enter(&pd->pd_mutex);
5498 5487 name_len = pd->pd_spn_len;
5499 5488 mutex_exit(&pd->pd_mutex);
5500 5489 }
5501 5490
5502 5491 pl_size = sizeof (fc_portid_t) + name_len + 1;
5503 5492
5504 5493 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5505 5494 sizeof (fc_reg_resp_t), sleep, NULL);
5506 5495 if (cmd == NULL) {
5507 5496 return (FC_NOMEM);
5508 5497 }
5509 5498
5510 5499 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5511 5500
5512 5501 pkt = &cmd->cmd_pkt;
5513 5502
5514 5503 spn = s_id;
5515 5504
5516 5505 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5517 5506 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5518 5507 DDI_DEV_AUTOINCR);
5519 5508 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5520 5509 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5521 5510 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5522 5511
5523 5512 if (pd == NULL) {
5524 5513 mutex_enter(&port->fp_mutex);
5525 5514 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5526 5515 (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5527 5516 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5528 5517 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5529 5518 mutex_exit(&port->fp_mutex);
5530 5519 } else {
5531 5520 mutex_enter(&pd->pd_mutex);
5532 5521 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5533 5522 (uint8_t *)pd->pd_spn,
5534 5523 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5535 5524 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5536 5525 mutex_exit(&pd->pd_mutex);
5537 5526 }
5538 5527 break;
5539 5528 }
5540 5529
5541 5530 case NS_RPT_ID: {
5542 5531 ns_rpt_t rpt;
5543 5532
5544 5533 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5545 5534 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5546 5535 if (cmd == NULL) {
5547 5536 return (FC_NOMEM);
5548 5537 }
5549 5538 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5550 5539 pkt = &cmd->cmd_pkt;
5551 5540
5552 5541 if (pd == NULL) {
5553 5542 rpt.rpt_type = port->fp_port_type;
5554 5543 } else {
5555 5544 mutex_enter(&pd->pd_mutex);
5556 5545 rpt.rpt_type = pd->pd_porttype;
5557 5546 mutex_exit(&pd->pd_mutex);
5558 5547 }
5559 5548 rpt.rpt_port_id = s_id;
5560 5549
5561 5550 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5562 5551 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5563 5552 sizeof (rpt), DDI_DEV_AUTOINCR);
5564 5553
5565 5554 break;
5566 5555 }
5567 5556
5568 5557 case NS_RIP_NN: {
5569 5558 ns_rip_t rip;
5570 5559
5571 5560 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5572 5561 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5573 5562 if (cmd == NULL) {
5574 5563 return (FC_NOMEM);
5575 5564 }
5576 5565 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5577 5566 pkt = &cmd->cmd_pkt;
5578 5567
5579 5568 if (pd == NULL) {
5580 5569 rip.rip_node_name =
5581 5570 port->fp_service_params.node_ww_name;
5582 5571 bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5583 5572 sizeof (port->fp_ip_addr));
5584 5573 } else {
5585 5574 fc_remote_node_t *node;
5586 5575
5587 5576 /*
5588 5577 * The most correct implementation should have the IP
5589 5578 * address in the fc_remote_node_t structure; I believe
5590 5579 * Node WWN and IP address should have one to one
5591 5580 * correlation (but guess what this is changing in
5592 5581 * FC-GS-2 latest draft)
5593 5582 */
5594 5583 mutex_enter(&pd->pd_mutex);
5595 5584 node = pd->pd_remote_nodep;
5596 5585 bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5597 5586 sizeof (pd->pd_ip_addr));
5598 5587 mutex_exit(&pd->pd_mutex);
5599 5588
5600 5589 mutex_enter(&node->fd_mutex);
5601 5590 rip.rip_node_name = node->fd_node_name;
5602 5591 mutex_exit(&node->fd_mutex);
5603 5592 }
5604 5593
5605 5594 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
5606 5595 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5607 5596 sizeof (rip), DDI_DEV_AUTOINCR);
5608 5597
5609 5598 break;
5610 5599 }
5611 5600
5612 5601 case NS_RIPA_NN: {
5613 5602 ns_ipa_t ipa;
5614 5603
5615 5604 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5616 5605 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5617 5606 if (cmd == NULL) {
5618 5607 return (FC_NOMEM);
5619 5608 }
5620 5609 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5621 5610 pkt = &cmd->cmd_pkt;
5622 5611
5623 5612 if (pd == NULL) {
5624 5613 ipa.ipa_node_name =
5625 5614 port->fp_service_params.node_ww_name;
5626 5615 bcopy(port->fp_ipa, ipa.ipa_value,
5627 5616 sizeof (port->fp_ipa));
5628 5617 } else {
5629 5618 fc_remote_node_t *node;
5630 5619
5631 5620 mutex_enter(&pd->pd_mutex);
5632 5621 node = pd->pd_remote_nodep;
5633 5622 mutex_exit(&pd->pd_mutex);
5634 5623
5635 5624 mutex_enter(&node->fd_mutex);
5636 5625 ipa.ipa_node_name = node->fd_node_name;
5637 5626 bcopy(node->fd_ipa, ipa.ipa_value,
5638 5627 sizeof (node->fd_ipa));
5639 5628 mutex_exit(&node->fd_mutex);
5640 5629 }
5641 5630
5642 5631 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5643 5632 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5644 5633 sizeof (ipa), DDI_DEV_AUTOINCR);
5645 5634
5646 5635 break;
5647 5636 }
5648 5637
5649 5638 case NS_RSNN_NN: {
5650 5639 uchar_t name_len;
5651 5640 int pl_size;
5652 5641 la_wwn_t snn;
5653 5642 fc_remote_node_t *node = NULL;
5654 5643
5655 5644 if (pd == NULL) {
5656 5645 mutex_enter(&port->fp_mutex);
5657 5646 name_len = port->fp_sym_node_namelen;
5658 5647 mutex_exit(&port->fp_mutex);
5659 5648 } else {
5660 5649 mutex_enter(&pd->pd_mutex);
5661 5650 node = pd->pd_remote_nodep;
5662 5651 mutex_exit(&pd->pd_mutex);
5663 5652
5664 5653 mutex_enter(&node->fd_mutex);
5665 5654 name_len = node->fd_snn_len;
5666 5655 mutex_exit(&node->fd_mutex);
5667 5656 }
5668 5657
5669 5658 pl_size = sizeof (la_wwn_t) + name_len + 1;
5670 5659
5671 5660 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5672 5661 pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5673 5662 if (cmd == NULL) {
5674 5663 return (FC_NOMEM);
5675 5664 }
5676 5665 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5677 5666
5678 5667 pkt = &cmd->cmd_pkt;
5679 5668
5680 5669 bcopy(&port->fp_service_params.node_ww_name,
5681 5670 &snn, sizeof (la_wwn_t));
5682 5671
5683 5672 if (pd == NULL) {
5684 5673 mutex_enter(&port->fp_mutex);
5685 5674 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5686 5675 (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5687 5676 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5688 5677 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5689 5678 mutex_exit(&port->fp_mutex);
5690 5679 } else {
5691 5680 ASSERT(node != NULL);
5692 5681 mutex_enter(&node->fd_mutex);
5693 5682 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5694 5683 (uint8_t *)node->fd_snn,
5695 5684 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5696 5685 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5697 5686 mutex_exit(&node->fd_mutex);
5698 5687 }
5699 5688
5700 5689 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
5701 5690 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5702 5691 sizeof (snn), DDI_DEV_AUTOINCR);
5703 5692 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5704 5693 (uint8_t *)(pkt->pkt_cmd
5705 5694 + sizeof (fc_ct_header_t) + sizeof (snn)),
5706 5695 1, DDI_DEV_AUTOINCR);
5707 5696
5708 5697 break;
5709 5698 }
5710 5699
5711 5700 case NS_DA_ID: {
5712 5701 ns_remall_t rall;
5713 5702 char tmp[4] = {0};
5714 5703 char *ptr;
5715 5704
5716 5705 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5717 5706 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5718 5707
5719 5708 if (cmd == NULL) {
5720 5709 return (FC_NOMEM);
5721 5710 }
5722 5711
5723 5712 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5724 5713 pkt = &cmd->cmd_pkt;
5725 5714
5726 5715 ptr = (char *)(&s_id);
5727 5716 tmp[3] = *ptr++;
5728 5717 tmp[2] = *ptr++;
5729 5718 tmp[1] = *ptr++;
5730 5719 tmp[0] = *ptr;
5731 5720 #if defined(_BIT_FIELDS_LTOH)
5732 5721 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5733 5722 #else
5734 5723 rall.rem_port_id = s_id;
5735 5724 #endif
5736 5725 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
5737 5726 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5738 5727 sizeof (rall), DDI_DEV_AUTOINCR);
5739 5728
5740 5729 break;
5741 5730 }
5742 5731
5743 5732 default:
5744 5733 return (FC_FAILURE);
5745 5734 }
5746 5735
5747 5736 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5748 5737
5749 5738 if (rval != FC_SUCCESS) {
5750 5739 job->job_result = rval;
5751 5740 fp_iodone(cmd);
5752 5741 }
5753 5742
5754 5743 if (polled) {
5755 5744 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5756 5745 fp_jobwait(job);
5757 5746 } else {
5758 5747 rval = FC_SUCCESS;
5759 5748 }
5760 5749
5761 5750 return (rval);
5762 5751 }
5763 5752
5764 5753
5765 5754 /*
5766 5755 * Common interrupt handler
5767 5756 */
5768 5757 static int
5769 5758 fp_common_intr(fc_packet_t *pkt, int iodone)
5770 5759 {
5771 5760 int rval = FC_FAILURE;
5772 5761 fp_cmd_t *cmd;
5773 5762 fc_local_port_t *port;
5774 5763
5775 5764 cmd = pkt->pkt_ulp_private;
5776 5765 port = cmd->cmd_port;
5777 5766
5778 5767 /*
5779 5768 * Fail fast the upper layer requests if
5780 5769 * a state change has occurred amidst.
5781 5770 */
5782 5771 mutex_enter(&port->fp_mutex);
5783 5772 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5784 5773 mutex_exit(&port->fp_mutex);
5785 5774 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5786 5775 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5787 5776 } else if (!(port->fp_soft_state &
5788 5777 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5789 5778 mutex_exit(&port->fp_mutex);
5790 5779
5791 5780 switch (pkt->pkt_state) {
5792 5781 case FC_PKT_LOCAL_BSY:
5793 5782 case FC_PKT_FABRIC_BSY:
5794 5783 case FC_PKT_NPORT_BSY:
5795 5784 case FC_PKT_TIMEOUT:
5796 5785 cmd->cmd_retry_interval = (pkt->pkt_state ==
5797 5786 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5798 5787 rval = fp_retry_cmd(pkt);
5799 5788 break;
5800 5789
5801 5790 case FC_PKT_FABRIC_RJT:
5802 5791 case FC_PKT_NPORT_RJT:
5803 5792 case FC_PKT_LOCAL_RJT:
5804 5793 case FC_PKT_LS_RJT:
5805 5794 case FC_PKT_FS_RJT:
5806 5795 case FC_PKT_BA_RJT:
5807 5796 rval = fp_handle_reject(pkt);
5808 5797 break;
5809 5798
5810 5799 default:
5811 5800 if (pkt->pkt_resp_resid) {
5812 5801 cmd->cmd_retry_interval = 0;
5813 5802 rval = fp_retry_cmd(pkt);
5814 5803 }
5815 5804 break;
5816 5805 }
5817 5806 } else {
5818 5807 mutex_exit(&port->fp_mutex);
5819 5808 }
5820 5809
5821 5810 if (rval != FC_SUCCESS && iodone) {
5822 5811 fp_iodone(cmd);
5823 5812 rval = FC_SUCCESS;
5824 5813 }
5825 5814
5826 5815 return (rval);
5827 5816 }
5828 5817
5829 5818
5830 5819 /*
5831 5820 * Some not so long winding theory on point to point topology:
5832 5821 *
5833 5822 * In the ACC payload, if the D_ID is ZERO and the common service
5834 5823 * parameters indicate N_Port, then the topology is POINT TO POINT.
5835 5824 *
5836 5825 * In a point to point topology with an N_Port, during Fabric Login,
5837 5826 * the destination N_Port will check with our WWN and decide if it
5838 5827 * needs to issue PLOGI or not. That means, FLOGI could potentially
5839 5828 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5840 5829 * PLOGI creates the device handles.
5841 5830 *
5842 5831 * Assuming that the host port WWN is greater than the other N_Port
5843 5832 * WWN, then we become the master (be aware that this isn't the word
5844 5833 * used in the FC standards) and initiate the PLOGI.
5845 5834 *
5846 5835 */
5847 5836 static void
5848 5837 fp_flogi_intr(fc_packet_t *pkt)
5849 5838 {
5850 5839 int state;
5851 5840 int f_port;
5852 5841 uint32_t s_id;
5853 5842 uint32_t d_id;
5854 5843 fp_cmd_t *cmd;
5855 5844 fc_local_port_t *port;
5856 5845 la_wwn_t *swwn;
5857 5846 la_wwn_t dwwn;
5858 5847 la_wwn_t nwwn;
5859 5848 fc_remote_port_t *pd;
5860 5849 la_els_logi_t *acc;
5861 5850 com_svc_t csp;
5862 5851 ls_code_t resp;
5863 5852
5864 5853 cmd = pkt->pkt_ulp_private;
5865 5854 port = cmd->cmd_port;
5866 5855
5867 5856 mutex_enter(&port->fp_mutex);
5868 5857 port->fp_out_fpcmds--;
5869 5858 mutex_exit(&port->fp_mutex);
5870 5859
5871 5860 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5872 5861 port, pkt, pkt->pkt_state);
5873 5862
5874 5863 if (FP_IS_PKT_ERROR(pkt)) {
5875 5864 (void) fp_common_intr(pkt, 1);
5876 5865 return;
5877 5866 }
5878 5867
5879 5868 /*
5880 5869 * Currently, we don't need to swap bytes here because qlc is faking the
5881 5870 * response for us and so endianness is getting taken care of. But we
5882 5871 * have to fix this and generalize this at some point
5883 5872 */
5884 5873 acc = (la_els_logi_t *)pkt->pkt_resp;
5885 5874
5886 5875 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5887 5876 sizeof (resp), DDI_DEV_AUTOINCR);
5888 5877
5889 5878 ASSERT(resp.ls_code == LA_ELS_ACC);
5890 5879 if (resp.ls_code != LA_ELS_ACC) {
5891 5880 (void) fp_common_intr(pkt, 1);
5892 5881 return;
5893 5882 }
5894 5883
5895 5884 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
5896 5885 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5897 5886
5898 5887 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5899 5888
5900 5889 ASSERT(!MUTEX_HELD(&port->fp_mutex));
5901 5890
5902 5891 mutex_enter(&port->fp_mutex);
5903 5892 state = FC_PORT_STATE_MASK(port->fp_state);
5904 5893 mutex_exit(&port->fp_mutex);
5905 5894
5906 5895 if (f_port == 0) {
5907 5896 if (state != FC_STATE_LOOP) {
5908 5897 swwn = &port->fp_service_params.nport_ww_name;
5909 5898
5910 5899 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5911 5900 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5912 5901 DDI_DEV_AUTOINCR);
5913 5902
5914 5903 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5915 5904 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5916 5905 DDI_DEV_AUTOINCR);
5917 5906
5918 5907 mutex_enter(&port->fp_mutex);
5919 5908
5920 5909 port->fp_topology = FC_TOP_PT_PT;
5921 5910 port->fp_total_devices = 1;
5922 5911 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5923 5912 port->fp_ptpt_master = 1;
5924 5913 /*
5925 5914 * Let us choose 'X' as S_ID and 'Y'
5926 5915 * as D_ID and that'll work; hopefully
5927 5916 * If not, it will get changed.
5928 5917 */
5929 5918 s_id = port->fp_instance + FP_DEFAULT_SID;
5930 5919 d_id = port->fp_instance + FP_DEFAULT_DID;
5931 5920 port->fp_port_id.port_id = s_id;
5932 5921 mutex_exit(&port->fp_mutex);
5933 5922
5934 5923 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
5935 5924 "pd %x", port->fp_port_id.port_id, d_id);
5936 5925 pd = fctl_create_remote_port(port,
5937 5926 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5938 5927 KM_NOSLEEP);
5939 5928 if (pd == NULL) {
5940 5929 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5941 5930 0, NULL, "couldn't create device"
5942 5931 " d_id=%X", d_id);
5943 5932 fp_iodone(cmd);
5944 5933 return;
5945 5934 }
5946 5935
5947 5936 cmd->cmd_pkt.pkt_tran_flags =
5948 5937 pkt->pkt_tran_flags;
5949 5938 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5950 5939 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5951 5940 cmd->cmd_retry_count = fp_retry_count;
5952 5941
5953 5942 fp_xlogi_init(port, cmd, s_id, d_id,
5954 5943 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5955 5944
5956 5945 (&cmd->cmd_pkt)->pkt_pd = pd;
5957 5946
5958 5947 /*
5959 5948 * We've just created this fc_remote_port_t, and
5960 5949 * we're about to use it to send a PLOGI, so
5961 5950 * bump the reference count right now. When
5962 5951 * the packet is freed, the reference count will
5963 5952 * be decremented. The ULP may also start using
5964 5953 * it, so mark it as given away as well.
5965 5954 */
5966 5955 pd->pd_ref_count++;
5967 5956 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5968 5957
5969 5958 if (fp_sendcmd(port, cmd,
5970 5959 port->fp_fca_handle) == FC_SUCCESS) {
5971 5960 return;
5972 5961 }
5973 5962 } else {
5974 5963 /*
5975 5964 * The device handles will be created when the
5976 5965 * unsolicited PLOGI is completed successfully
5977 5966 */
5978 5967 port->fp_ptpt_master = 0;
5979 5968 mutex_exit(&port->fp_mutex);
5980 5969 }
5981 5970 }
5982 5971 pkt->pkt_state = FC_PKT_FAILURE;
5983 5972 } else {
5984 5973 if (f_port) {
5985 5974 mutex_enter(&port->fp_mutex);
5986 5975 if (state == FC_STATE_LOOP) {
5987 5976 port->fp_topology = FC_TOP_PUBLIC_LOOP;
5988 5977 } else {
5989 5978 port->fp_topology = FC_TOP_FABRIC;
5990 5979
5991 5980 FC_GET_RSP(port, pkt->pkt_resp_acc,
5992 5981 (uint8_t *)&port->fp_fabric_name,
5993 5982 (uint8_t *)&acc->node_ww_name,
5994 5983 sizeof (la_wwn_t),
5995 5984 DDI_DEV_AUTOINCR);
5996 5985 }
5997 5986 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5998 5987 mutex_exit(&port->fp_mutex);
5999 5988 } else {
6000 5989 pkt->pkt_state = FC_PKT_FAILURE;
6001 5990 }
6002 5991 }
6003 5992 fp_iodone(cmd);
6004 5993 }
6005 5994
6006 5995
6007 5996 /*
6008 5997 * Handle solicited PLOGI response
6009 5998 */
6010 5999 static void
6011 6000 fp_plogi_intr(fc_packet_t *pkt)
6012 6001 {
6013 6002 int nl_port;
6014 6003 int bailout;
6015 6004 uint32_t d_id;
6016 6005 fp_cmd_t *cmd;
6017 6006 la_els_logi_t *acc;
6018 6007 fc_local_port_t *port;
↓ open down ↓ |
1786 lines elided |
↑ open up ↑ |
6019 6008 fc_remote_port_t *pd;
6020 6009 la_wwn_t nwwn;
6021 6010 la_wwn_t pwwn;
6022 6011 ls_code_t resp;
6023 6012
6024 6013 nl_port = 0;
6025 6014 cmd = pkt->pkt_ulp_private;
6026 6015 port = cmd->cmd_port;
6027 6016 d_id = pkt->pkt_cmd_fhdr.d_id;
6028 6017
6029 -#ifndef __lock_lint
6030 6018 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6031 -#endif
6032 6019
6033 6020 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
6034 6021 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
6035 6022 cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
6036 6023
6037 6024 /*
6038 6025 * Bail out early on ULP initiated requests if the
6039 6026 * state change has occurred
6040 6027 */
6041 6028 mutex_enter(&port->fp_mutex);
6042 6029 port->fp_out_fpcmds--;
6043 6030 bailout = ((port->fp_statec_busy ||
6044 6031 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6045 6032 cmd->cmd_ulp_pkt) ? 1 : 0;
6046 6033 mutex_exit(&port->fp_mutex);
6047 6034
6048 6035 if (FP_IS_PKT_ERROR(pkt) || bailout) {
6049 6036 int skip_msg = 0;
6050 6037 int giveup = 0;
6051 6038
6052 6039 if (cmd->cmd_ulp_pkt) {
6053 6040 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6054 6041 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
6055 6042 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6056 6043 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6057 6044 }
6058 6045
6059 6046 /*
6060 6047 * If an unsolicited cross login already created
6061 6048 * a device speed up the discovery by not retrying
6062 6049 * the command mindlessly.
6063 6050 */
6064 6051 if (pkt->pkt_pd == NULL &&
6065 6052 fctl_get_remote_port_by_did(port, d_id) != NULL) {
6066 6053 fp_iodone(cmd);
6067 6054 return;
6068 6055 }
6069 6056
6070 6057 if (pkt->pkt_pd != NULL) {
6071 6058 giveup = (pkt->pkt_pd->pd_recepient ==
6072 6059 PD_PLOGI_RECEPIENT) ? 1 : 0;
6073 6060 if (giveup) {
6074 6061 /*
6075 6062 * This pd is marked as plogi
6076 6063 * recipient, stop retrying
6077 6064 */
6078 6065 FP_TRACE(FP_NHEAD1(3, 0),
6079 6066 "fp_plogi_intr: stop retry as"
6080 6067 " a cross login was accepted"
6081 6068 " from d_id=%x, port=%p.",
6082 6069 d_id, port);
6083 6070 fp_iodone(cmd);
6084 6071 return;
6085 6072 }
6086 6073 }
6087 6074
6088 6075 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6089 6076 return;
6090 6077 }
6091 6078
6092 6079 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
6093 6080 mutex_enter(&pd->pd_mutex);
6094 6081 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
6095 6082 skip_msg++;
6096 6083 }
6097 6084 mutex_exit(&pd->pd_mutex);
6098 6085 }
6099 6086
6100 6087 mutex_enter(&port->fp_mutex);
6101 6088 if (!bailout && !(skip_msg && port->fp_statec_busy) &&
6102 6089 port->fp_statec_busy <= 1 &&
6103 6090 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
6104 6091 mutex_exit(&port->fp_mutex);
6105 6092 /*
6106 6093 * In case of Login Collisions, JNI HBAs returns the
6107 6094 * FC pkt back to the Initiator with the state set to
6108 6095 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
6109 6096 * QLC HBAs handles such cases in the FW and doesnot
6110 6097 * return the LS_RJT with Logical error when
6111 6098 * login collision happens.
6112 6099 */
6113 6100 if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6114 6101 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6115 6102 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6116 6103 "PLOGI to %x failed", d_id);
6117 6104 }
6118 6105 FP_TRACE(FP_NHEAD2(9, 0),
6119 6106 "PLOGI to %x failed. state=%x reason=%x.",
6120 6107 d_id, pkt->pkt_state, pkt->pkt_reason);
6121 6108 } else {
6122 6109 mutex_exit(&port->fp_mutex);
6123 6110 }
6124 6111
6125 6112 fp_iodone(cmd);
6126 6113 return;
6127 6114 }
6128 6115
6129 6116 acc = (la_els_logi_t *)pkt->pkt_resp;
6130 6117
6131 6118 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6132 6119 sizeof (resp), DDI_DEV_AUTOINCR);
6133 6120
6134 6121 ASSERT(resp.ls_code == LA_ELS_ACC);
6135 6122 if (resp.ls_code != LA_ELS_ACC) {
6136 6123 (void) fp_common_intr(pkt, 1);
6137 6124 return;
6138 6125 }
6139 6126
6140 6127 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6141 6128 mutex_enter(&port->fp_mutex);
6142 6129 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6143 6130 mutex_exit(&port->fp_mutex);
6144 6131 fp_iodone(cmd);
6145 6132 return;
6146 6133 }
6147 6134
6148 6135 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6149 6136
6150 6137 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6151 6138 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6152 6139 DDI_DEV_AUTOINCR);
6153 6140
6154 6141 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6155 6142 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6156 6143 DDI_DEV_AUTOINCR);
6157 6144
6158 6145 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6159 6146 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6160 6147
6161 6148 if ((pd = pkt->pkt_pd) == NULL) {
6162 6149 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6163 6150 if (pd == NULL) {
6164 6151 FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x",
6165 6152 port->fp_port_id.port_id, d_id);
6166 6153 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6167 6154 PD_PLOGI_INITIATOR, KM_NOSLEEP);
6168 6155 if (pd == NULL) {
6169 6156 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6170 6157 "couldn't create port device handles"
6171 6158 " d_id=%x", d_id);
6172 6159 fp_iodone(cmd);
6173 6160 return;
6174 6161 }
6175 6162 } else {
6176 6163 fc_remote_port_t *tmp_pd;
6177 6164
6178 6165 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6179 6166 if (tmp_pd != NULL) {
6180 6167 fp_iodone(cmd);
6181 6168 return;
6182 6169 }
6183 6170
6184 6171 mutex_enter(&port->fp_mutex);
6185 6172 mutex_enter(&pd->pd_mutex);
6186 6173 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6187 6174 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6188 6175 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6189 6176 }
6190 6177
6191 6178 if (pd->pd_type == PORT_DEVICE_OLD) {
6192 6179 if (pd->pd_port_id.port_id != d_id) {
6193 6180 fctl_delist_did_table(port, pd);
6194 6181 pd->pd_type = PORT_DEVICE_CHANGED;
6195 6182 pd->pd_port_id.port_id = d_id;
6196 6183 } else {
6197 6184 pd->pd_type = PORT_DEVICE_NOCHANGE;
6198 6185 }
6199 6186 }
6200 6187
6201 6188 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6202 6189 char ww_name[17];
6203 6190
6204 6191 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6205 6192
6206 6193 mutex_exit(&pd->pd_mutex);
6207 6194 mutex_exit(&port->fp_mutex);
6208 6195 FP_TRACE(FP_NHEAD2(9, 0),
6209 6196 "Possible Duplicate name or address"
6210 6197 " identifiers in the PLOGI response"
6211 6198 " D_ID=%x, PWWN=%s: Please check the"
6212 6199 " configuration", d_id, ww_name);
6213 6200 fp_iodone(cmd);
6214 6201 return;
6215 6202 }
6216 6203 fctl_enlist_did_table(port, pd);
6217 6204 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6218 6205 mutex_exit(&pd->pd_mutex);
6219 6206 mutex_exit(&port->fp_mutex);
6220 6207 }
6221 6208 } else {
6222 6209 fc_remote_port_t *tmp_pd, *new_wwn_pd;
6223 6210
6224 6211 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6225 6212 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6226 6213
6227 6214 mutex_enter(&port->fp_mutex);
6228 6215 mutex_enter(&pd->pd_mutex);
6229 6216 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6230 6217 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6231 6218 " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6232 6219 pd->pd_type);
6233 6220 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6234 6221 pd->pd_type == PORT_DEVICE_OLD) ||
6235 6222 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6236 6223 pd->pd_type = PORT_DEVICE_NOCHANGE;
6237 6224 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6238 6225 pd->pd_type = PORT_DEVICE_NEW;
6239 6226 }
6240 6227 } else {
6241 6228 char old_name[17];
6242 6229 char new_name[17];
6243 6230
6244 6231 fc_wwn_to_str(&pd->pd_port_name, old_name);
6245 6232 fc_wwn_to_str(&pwwn, new_name);
6246 6233
6247 6234 FP_TRACE(FP_NHEAD1(9, 0),
6248 6235 "fp_plogi_intr: PWWN of a device with D_ID=%x "
6249 6236 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6250 6237 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6251 6238 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6252 6239 cmd->cmd_ulp_pkt, bailout);
6253 6240
6254 6241 FP_TRACE(FP_NHEAD2(9, 0),
6255 6242 "PWWN of a device with D_ID=%x changed."
6256 6243 " New PWWN = %s, OLD PWWN = %s", d_id,
6257 6244 new_name, old_name);
6258 6245
6259 6246 if (cmd->cmd_ulp_pkt && !bailout) {
6260 6247 fc_remote_node_t *rnodep;
6261 6248 fc_portmap_t *changelist;
6262 6249 fc_portmap_t *listptr;
6263 6250 int len = 1;
6264 6251 /* # entries in changelist */
6265 6252
6266 6253 fctl_delist_pwwn_table(port, pd);
6267 6254
6268 6255 /*
6269 6256 * Lets now check if there already is a pd with
6270 6257 * this new WWN in the table. If so, we'll mark
6271 6258 * it as invalid
6272 6259 */
6273 6260
6274 6261 if (new_wwn_pd) {
6275 6262 /*
6276 6263 * There is another pd with in the pwwn
6277 6264 * table with the same WWN that we got
6278 6265 * in the PLOGI payload. We have to get
6279 6266 * it out of the pwwn table, update the
6280 6267 * pd's state (fp_fillout_old_map does
6281 6268 * this for us) and add it to the
6282 6269 * changelist that goes up to ULPs.
6283 6270 *
6284 6271 * len is length of changelist and so
6285 6272 * increment it.
6286 6273 */
6287 6274 len++;
6288 6275
6289 6276 if (tmp_pd != pd) {
6290 6277 /*
6291 6278 * Odd case where pwwn and did
6292 6279 * tables are out of sync but
6293 6280 * we will handle that too. See
6294 6281 * more comments below.
6295 6282 *
6296 6283 * One more device that ULPs
6297 6284 * should know about and so len
6298 6285 * gets incremented again.
6299 6286 */
6300 6287 len++;
6301 6288 }
6302 6289
6303 6290 listptr = changelist = kmem_zalloc(len *
6304 6291 sizeof (*changelist), KM_SLEEP);
6305 6292
6306 6293 mutex_enter(&new_wwn_pd->pd_mutex);
6307 6294 rnodep = new_wwn_pd->pd_remote_nodep;
6308 6295 mutex_exit(&new_wwn_pd->pd_mutex);
6309 6296
6310 6297 /*
6311 6298 * Hold the fd_mutex since
6312 6299 * fctl_copy_portmap_held expects it.
6313 6300 * Preserve lock hierarchy by grabbing
6314 6301 * fd_mutex before pd_mutex
6315 6302 */
6316 6303 if (rnodep) {
6317 6304 mutex_enter(&rnodep->fd_mutex);
6318 6305 }
6319 6306 mutex_enter(&new_wwn_pd->pd_mutex);
6320 6307 fp_fillout_old_map_held(listptr++,
6321 6308 new_wwn_pd, 0);
6322 6309 mutex_exit(&new_wwn_pd->pd_mutex);
6323 6310 if (rnodep) {
6324 6311 mutex_exit(&rnodep->fd_mutex);
6325 6312 }
6326 6313
6327 6314 /*
6328 6315 * Safety check :
6329 6316 * Lets ensure that the pwwn and did
6330 6317 * tables are in sync. Ideally, we
6331 6318 * should not find that these two pd's
6332 6319 * are different.
6333 6320 */
6334 6321 if (tmp_pd != pd) {
6335 6322 mutex_enter(&tmp_pd->pd_mutex);
6336 6323 rnodep =
6337 6324 tmp_pd->pd_remote_nodep;
6338 6325 mutex_exit(&tmp_pd->pd_mutex);
6339 6326
6340 6327 /* As above grab fd_mutex */
6341 6328 if (rnodep) {
6342 6329 mutex_enter(&rnodep->
6343 6330 fd_mutex);
6344 6331 }
6345 6332 mutex_enter(&tmp_pd->pd_mutex);
6346 6333
6347 6334 fp_fillout_old_map_held(
6348 6335 listptr++, tmp_pd, 0);
6349 6336
6350 6337 mutex_exit(&tmp_pd->pd_mutex);
6351 6338 if (rnodep) {
6352 6339 mutex_exit(&rnodep->
6353 6340 fd_mutex);
6354 6341 }
6355 6342
6356 6343 /*
6357 6344 * Now add "pd" (not tmp_pd)
6358 6345 * to fp_did_table to sync it up
6359 6346 * with fp_pwwn_table
6360 6347 *
6361 6348 * pd->pd_mutex is already held
6362 6349 * at this point
6363 6350 */
6364 6351 fctl_enlist_did_table(port, pd);
6365 6352 }
6366 6353 } else {
6367 6354 listptr = changelist = kmem_zalloc(
6368 6355 sizeof (*changelist), KM_SLEEP);
6369 6356 }
6370 6357
6371 6358 ASSERT(changelist != NULL);
6372 6359
6373 6360 fp_fillout_changed_map(listptr, pd, &d_id,
6374 6361 &pwwn);
6375 6362 fctl_enlist_pwwn_table(port, pd);
6376 6363
6377 6364 mutex_exit(&pd->pd_mutex);
6378 6365 mutex_exit(&port->fp_mutex);
6379 6366
6380 6367 fp_iodone(cmd);
6381 6368
6382 6369 (void) fp_ulp_devc_cb(port, changelist, len,
6383 6370 len, KM_NOSLEEP, 0);
6384 6371
6385 6372 return;
6386 6373 }
6387 6374 }
6388 6375
6389 6376 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6390 6377 nl_port = 1;
6391 6378 }
6392 6379 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6393 6380 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6394 6381 }
6395 6382
6396 6383 mutex_exit(&pd->pd_mutex);
6397 6384 mutex_exit(&port->fp_mutex);
6398 6385
6399 6386 if (tmp_pd == NULL) {
6400 6387 mutex_enter(&port->fp_mutex);
6401 6388 mutex_enter(&pd->pd_mutex);
6402 6389 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6403 6390 char ww_name[17];
6404 6391
6405 6392 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6406 6393 mutex_exit(&pd->pd_mutex);
6407 6394 mutex_exit(&port->fp_mutex);
6408 6395 FP_TRACE(FP_NHEAD2(9, 0),
6409 6396 "Possible Duplicate name or address"
6410 6397 " identifiers in the PLOGI response"
6411 6398 " D_ID=%x, PWWN=%s: Please check the"
6412 6399 " configuration", d_id, ww_name);
6413 6400 fp_iodone(cmd);
6414 6401 return;
6415 6402 }
6416 6403 fctl_enlist_did_table(port, pd);
6417 6404 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6418 6405 mutex_exit(&pd->pd_mutex);
6419 6406 mutex_exit(&port->fp_mutex);
6420 6407 }
6421 6408 }
6422 6409 fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6423 6410 FC_TRAN_CLASS(pkt->pkt_tran_flags));
6424 6411
6425 6412 if (cmd->cmd_ulp_pkt) {
6426 6413 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6427 6414 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6428 6415 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6429 6416 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6430 6417 if (pd != NULL) {
6431 6418 FP_TRACE(FP_NHEAD1(9, 0),
6432 6419 "fp_plogi_intr;"
6433 6420 "ulp_pkt's pd is NULL, get a pd %p",
6434 6421 pd);
6435 6422 mutex_enter(&pd->pd_mutex);
6436 6423 pd->pd_ref_count++;
6437 6424 mutex_exit(&pd->pd_mutex);
6438 6425 }
6439 6426 cmd->cmd_ulp_pkt->pkt_pd = pd;
6440 6427 }
6441 6428 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6442 6429 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6443 6430 sizeof (fc_frame_hdr_t));
6444 6431 bcopy((caddr_t)pkt->pkt_resp,
6445 6432 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6446 6433 sizeof (la_els_logi_t));
6447 6434 }
6448 6435
6449 6436 mutex_enter(&port->fp_mutex);
6450 6437 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6451 6438 mutex_enter(&pd->pd_mutex);
6452 6439
6453 6440 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6454 6441 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6455 6442 cmd->cmd_retry_count = fp_retry_count;
6456 6443
6457 6444 /*
6458 6445 * If the fc_remote_port_t pointer is not set in the given
6459 6446 * fc_packet_t, then this fc_remote_port_t must have just
6460 6447 * been created. Save the pointer and also increment the
6461 6448 * fc_remote_port_t reference count.
6462 6449 */
6463 6450 if (pkt->pkt_pd == NULL) {
6464 6451 pkt->pkt_pd = pd;
6465 6452 pd->pd_ref_count++; /* It's in use! */
6466 6453 }
6467 6454
6468 6455 fp_adisc_init(cmd, cmd->cmd_job);
6469 6456
6470 6457 pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6471 6458 pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6472 6459
6473 6460 mutex_exit(&pd->pd_mutex);
6474 6461 mutex_exit(&port->fp_mutex);
6475 6462
6476 6463 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6477 6464 return;
6478 6465 }
6479 6466 } else {
6480 6467 mutex_exit(&port->fp_mutex);
6481 6468 }
6482 6469
6483 6470 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6484 6471 mutex_enter(&port->fp_mutex);
6485 6472 mutex_enter(&pd->pd_mutex);
6486 6473
6487 6474 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6488 6475 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6489 6476 cmd->cmd_retry_count = fp_retry_count;
6490 6477
6491 6478 fp_logo_init(pd, cmd, cmd->cmd_job);
6492 6479
6493 6480 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6494 6481 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6495 6482
6496 6483 mutex_exit(&pd->pd_mutex);
6497 6484 mutex_exit(&port->fp_mutex);
6498 6485
6499 6486 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6500 6487 return;
6501 6488 }
6502 6489
6503 6490 }
6504 6491 fp_iodone(cmd);
6505 6492 }
6506 6493
6507 6494
6508 6495 /*
6509 6496 * Handle solicited ADISC response
6510 6497 */
6511 6498 static void
6512 6499 fp_adisc_intr(fc_packet_t *pkt)
6513 6500 {
6514 6501 int rval;
6515 6502 int bailout;
6516 6503 fp_cmd_t *cmd, *logi_cmd;
6517 6504 fc_local_port_t *port;
6518 6505 fc_remote_port_t *pd;
↓ open down ↓ |
477 lines elided |
↑ open up ↑ |
6519 6506 la_els_adisc_t *acc;
6520 6507 ls_code_t resp;
6521 6508 fc_hardaddr_t ha;
6522 6509 fc_portmap_t *changelist;
6523 6510 int initiator, adiscfail = 0;
6524 6511
6525 6512 pd = pkt->pkt_pd;
6526 6513 cmd = pkt->pkt_ulp_private;
6527 6514 port = cmd->cmd_port;
6528 6515
6529 -#ifndef __lock_lint
6530 6516 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6531 -#endif
6532 6517
6533 6518 ASSERT(pd != NULL && port != NULL && cmd != NULL);
6534 6519
6535 6520 mutex_enter(&port->fp_mutex);
6536 6521 port->fp_out_fpcmds--;
6537 6522 bailout = ((port->fp_statec_busy ||
6538 6523 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6539 6524 cmd->cmd_ulp_pkt) ? 1 : 0;
6540 6525 mutex_exit(&port->fp_mutex);
6541 6526
6542 6527 if (bailout) {
6543 6528 fp_iodone(cmd);
6544 6529 return;
6545 6530 }
6546 6531
6547 6532 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6548 6533 acc = (la_els_adisc_t *)pkt->pkt_resp;
6549 6534
6550 6535 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6551 6536 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6552 6537
6553 6538 if (resp.ls_code == LA_ELS_ACC) {
6554 6539 int is_private;
6555 6540
6556 6541 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
6557 6542 (uint8_t *)&acc->hard_addr, sizeof (ha),
6558 6543 DDI_DEV_AUTOINCR);
6559 6544
6560 6545 mutex_enter(&port->fp_mutex);
6561 6546
6562 6547 is_private =
6563 6548 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6564 6549
6565 6550 mutex_enter(&pd->pd_mutex);
6566 6551 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6567 6552 fctl_enlist_did_table(port, pd);
6568 6553 }
6569 6554 mutex_exit(&pd->pd_mutex);
6570 6555
6571 6556 mutex_exit(&port->fp_mutex);
6572 6557
6573 6558 mutex_enter(&pd->pd_mutex);
6574 6559 if (pd->pd_type != PORT_DEVICE_NEW) {
6575 6560 if (is_private && (pd->pd_hard_addr.hard_addr !=
6576 6561 ha.hard_addr)) {
6577 6562 pd->pd_type = PORT_DEVICE_CHANGED;
6578 6563 } else {
6579 6564 pd->pd_type = PORT_DEVICE_NOCHANGE;
6580 6565 }
6581 6566 }
6582 6567
6583 6568 if (is_private && (ha.hard_addr &&
6584 6569 pd->pd_port_id.port_id != ha.hard_addr)) {
6585 6570 char ww_name[17];
6586 6571
6587 6572 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6588 6573
6589 6574 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6590 6575 "NL_Port Identifier %x doesn't match"
6591 6576 " with Hard Address %x, Will use Port"
6592 6577 " WWN %s", pd->pd_port_id.port_id,
6593 6578 ha.hard_addr, ww_name);
6594 6579
6595 6580 pd->pd_hard_addr.hard_addr = 0;
6596 6581 } else {
6597 6582 pd->pd_hard_addr.hard_addr = ha.hard_addr;
6598 6583 }
6599 6584 mutex_exit(&pd->pd_mutex);
6600 6585 } else {
6601 6586 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6602 6587 return;
6603 6588 }
6604 6589 }
6605 6590 } else {
6606 6591 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6607 6592 return;
6608 6593 }
6609 6594
6610 6595 mutex_enter(&port->fp_mutex);
6611 6596 if (port->fp_statec_busy <= 1) {
6612 6597 mutex_exit(&port->fp_mutex);
6613 6598 if (pkt->pkt_state == FC_PKT_LS_RJT &&
6614 6599 pkt->pkt_reason == FC_REASON_CMD_UNABLE) {
6615 6600 uchar_t class;
6616 6601 int cmd_flag;
6617 6602 uint32_t src_id;
6618 6603
6619 6604 class = fp_get_nextclass(port,
6620 6605 FC_TRAN_CLASS_INVALID);
6621 6606 if (class == FC_TRAN_CLASS_INVALID) {
6622 6607 fp_iodone(cmd);
6623 6608 return;
6624 6609 }
6625 6610
6626 6611 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; "
6627 6612 "fp_state=0x%x, pkt_state=0x%x, "
6628 6613 "reason=0x%x, class=0x%x",
6629 6614 port->fp_state, pkt->pkt_state,
6630 6615 pkt->pkt_reason, class);
6631 6616 cmd_flag = FP_CMD_PLOGI_RETAIN;
6632 6617
6633 6618 logi_cmd = fp_alloc_pkt(port,
6634 6619 sizeof (la_els_logi_t),
6635 6620 sizeof (la_els_logi_t), KM_SLEEP, pd);
6636 6621 if (logi_cmd == NULL) {
6637 6622 fp_iodone(cmd);
6638 6623 return;
6639 6624 }
6640 6625
6641 6626 logi_cmd->cmd_pkt.pkt_tran_flags =
6642 6627 FC_TRAN_INTR | class;
6643 6628 logi_cmd->cmd_pkt.pkt_tran_type =
6644 6629 FC_PKT_EXCHANGE;
6645 6630 logi_cmd->cmd_flags = cmd_flag;
6646 6631 logi_cmd->cmd_retry_count = fp_retry_count;
6647 6632 logi_cmd->cmd_ulp_pkt = NULL;
6648 6633
6649 6634 mutex_enter(&port->fp_mutex);
6650 6635 src_id = port->fp_port_id.port_id;
6651 6636 mutex_exit(&port->fp_mutex);
6652 6637
6653 6638 fp_xlogi_init(port, logi_cmd, src_id,
6654 6639 pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr,
6655 6640 cmd->cmd_job, LA_ELS_PLOGI);
6656 6641 if (pd) {
6657 6642 mutex_enter(&pd->pd_mutex);
6658 6643 pd->pd_flags = PD_ELS_IN_PROGRESS;
6659 6644 mutex_exit(&pd->pd_mutex);
6660 6645 }
6661 6646
6662 6647 if (fp_sendcmd(port, logi_cmd,
6663 6648 port->fp_fca_handle) == FC_SUCCESS) {
6664 6649 fp_free_pkt(cmd);
6665 6650 return;
6666 6651 } else {
6667 6652 fp_free_pkt(logi_cmd);
6668 6653 }
6669 6654 } else {
6670 6655 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6671 6656 "ADISC to %x failed, cmd_flags=%x",
6672 6657 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6673 6658 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6674 6659 adiscfail = 1;
6675 6660 }
6676 6661 } else {
6677 6662 mutex_exit(&port->fp_mutex);
6678 6663 }
6679 6664 }
6680 6665
6681 6666 if (cmd->cmd_ulp_pkt) {
6682 6667 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6683 6668 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6684 6669 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6685 6670 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6686 6671 cmd->cmd_ulp_pkt->pkt_pd = pd;
6687 6672 FP_TRACE(FP_NHEAD1(9, 0),
6688 6673 "fp_adisc__intr;"
6689 6674 "ulp_pkt's pd is NULL, get a pd %p",
6690 6675 pd);
6691 6676
6692 6677 }
6693 6678 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6694 6679 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6695 6680 sizeof (fc_frame_hdr_t));
6696 6681 bcopy((caddr_t)pkt->pkt_resp,
6697 6682 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6698 6683 sizeof (la_els_adisc_t));
6699 6684 }
6700 6685
6701 6686 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6702 6687 FP_TRACE(FP_NHEAD1(9, 0),
6703 6688 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6704 6689 "fp_retry_count=%x, ulp_pkt=%p",
6705 6690 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6706 6691
6707 6692 mutex_enter(&port->fp_mutex);
6708 6693 mutex_enter(&pd->pd_mutex);
6709 6694
6710 6695 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6711 6696 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6712 6697 cmd->cmd_retry_count = fp_retry_count;
6713 6698
6714 6699 fp_logo_init(pd, cmd, cmd->cmd_job);
6715 6700
6716 6701 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6717 6702 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6718 6703
6719 6704 mutex_exit(&pd->pd_mutex);
6720 6705 mutex_exit(&port->fp_mutex);
6721 6706
6722 6707 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6723 6708 if (adiscfail) {
6724 6709 mutex_enter(&pd->pd_mutex);
6725 6710 initiator =
6726 6711 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
6727 6712 pd->pd_state = PORT_DEVICE_VALID;
6728 6713 pd->pd_aux_flags |= PD_LOGGED_OUT;
6729 6714 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6730 6715 pd->pd_type = PORT_DEVICE_NEW;
6731 6716 } else {
6732 6717 pd->pd_type = PORT_DEVICE_NOCHANGE;
6733 6718 }
6734 6719 mutex_exit(&pd->pd_mutex);
6735 6720
6736 6721 changelist =
6737 6722 kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6738 6723
6739 6724 if (initiator) {
6740 6725 fp_unregister_login(pd);
6741 6726 fctl_copy_portmap(changelist, pd);
6742 6727 } else {
6743 6728 fp_fillout_old_map(changelist, pd, 0);
6744 6729 }
6745 6730
6746 6731 FP_TRACE(FP_NHEAD1(9, 0),
6747 6732 "fp_adisc_intr: Dev change notification "
6748 6733 "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6749 6734 "map_flags=%x initiator=%d", port, pd,
6750 6735 changelist->map_type, changelist->map_state,
6751 6736 changelist->map_flags, initiator);
6752 6737
6753 6738 (void) fp_ulp_devc_cb(port, changelist,
6754 6739 1, 1, KM_SLEEP, 0);
6755 6740 }
6756 6741 if (rval == FC_SUCCESS) {
6757 6742 return;
6758 6743 }
6759 6744 }
6760 6745 fp_iodone(cmd);
6761 6746 }
6762 6747
6763 6748
6764 6749 /*
6765 6750 * Handle solicited LOGO response
6766 6751 */
6767 6752 static void
6768 6753 fp_logo_intr(fc_packet_t *pkt)
6769 6754 {
6770 6755 ls_code_t resp;
6771 6756 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6772 6757
6773 6758 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6774 6759 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6775 6760 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6776 6761
6777 6762 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6778 6763 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6779 6764
6780 6765 if (FP_IS_PKT_ERROR(pkt)) {
6781 6766 (void) fp_common_intr(pkt, 1);
6782 6767 return;
6783 6768 }
6784 6769
6785 6770 ASSERT(resp.ls_code == LA_ELS_ACC);
6786 6771 if (resp.ls_code != LA_ELS_ACC) {
6787 6772 (void) fp_common_intr(pkt, 1);
6788 6773 return;
6789 6774 }
6790 6775
6791 6776 if (pkt->pkt_pd != NULL) {
6792 6777 fp_unregister_login(pkt->pkt_pd);
6793 6778 }
6794 6779
6795 6780 fp_iodone(pkt->pkt_ulp_private);
6796 6781 }
6797 6782
6798 6783
6799 6784 /*
6800 6785 * Handle solicited RNID response
6801 6786 */
6802 6787 static void
6803 6788 fp_rnid_intr(fc_packet_t *pkt)
6804 6789 {
6805 6790 ls_code_t resp;
6806 6791 job_request_t *job;
6807 6792 fp_cmd_t *cmd;
6808 6793 la_els_rnid_acc_t *acc;
6809 6794 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6810 6795
6811 6796 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6812 6797 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6813 6798 cmd = pkt->pkt_ulp_private;
6814 6799
6815 6800 mutex_enter(&cmd->cmd_port->fp_mutex);
6816 6801 cmd->cmd_port->fp_out_fpcmds--;
6817 6802 mutex_exit(&cmd->cmd_port->fp_mutex);
6818 6803
6819 6804 job = cmd->cmd_job;
6820 6805 ASSERT(job->job_private != NULL);
6821 6806
6822 6807 /* If failure or LS_RJT then retry the packet, if needed */
6823 6808 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6824 6809 (void) fp_common_intr(pkt, 1);
6825 6810 return;
6826 6811 }
6827 6812
6828 6813 /* Save node_id memory allocated in ioctl code */
6829 6814 acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6830 6815
6831 6816 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6832 6817 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6833 6818
6834 6819 /* wakeup the ioctl thread and free the pkt */
6835 6820 fp_iodone(cmd);
6836 6821 }
6837 6822
6838 6823
6839 6824 /*
6840 6825 * Handle solicited RLS response
6841 6826 */
6842 6827 static void
6843 6828 fp_rls_intr(fc_packet_t *pkt)
6844 6829 {
6845 6830 ls_code_t resp;
6846 6831 job_request_t *job;
6847 6832 fp_cmd_t *cmd;
6848 6833 la_els_rls_acc_t *acc;
6849 6834 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6850 6835
6851 6836 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6852 6837 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6853 6838 cmd = pkt->pkt_ulp_private;
6854 6839
6855 6840 mutex_enter(&cmd->cmd_port->fp_mutex);
6856 6841 cmd->cmd_port->fp_out_fpcmds--;
6857 6842 mutex_exit(&cmd->cmd_port->fp_mutex);
6858 6843
6859 6844 job = cmd->cmd_job;
6860 6845 ASSERT(job->job_private != NULL);
6861 6846
6862 6847 /* If failure or LS_RJT then retry the packet, if needed */
6863 6848 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6864 6849 (void) fp_common_intr(pkt, 1);
6865 6850 return;
6866 6851 }
6867 6852
6868 6853 /* Save link error status block in memory allocated in ioctl code */
6869 6854 acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6870 6855
6871 6856 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6872 6857 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6873 6858 DDI_DEV_AUTOINCR);
6874 6859
6875 6860 /* wakeup the ioctl thread and free the pkt */
6876 6861 fp_iodone(cmd);
6877 6862 }
6878 6863
6879 6864
6880 6865 /*
6881 6866 * A solicited command completion interrupt (mostly for commands
6882 6867 * that require almost no post processing such as SCR ELS)
6883 6868 */
6884 6869 static void
6885 6870 fp_intr(fc_packet_t *pkt)
6886 6871 {
6887 6872 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6888 6873 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6889 6874 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6890 6875
6891 6876 if (FP_IS_PKT_ERROR(pkt)) {
6892 6877 (void) fp_common_intr(pkt, 1);
6893 6878 return;
6894 6879 }
6895 6880 fp_iodone(pkt->pkt_ulp_private);
6896 6881 }
6897 6882
6898 6883
6899 6884 /*
6900 6885 * Handle the underlying port's state change
6901 6886 */
6902 6887 static void
6903 6888 fp_statec_cb(opaque_t port_handle, uint32_t state)
6904 6889 {
6905 6890 fc_local_port_t *port = port_handle;
6906 6891 job_request_t *job;
6907 6892
6908 6893 /*
6909 6894 * If it is not possible to process the callbacks
6910 6895 * just drop the callback on the floor; Don't bother
6911 6896 * to do something that isn't safe at this time
6912 6897 */
6913 6898 mutex_enter(&port->fp_mutex);
6914 6899 if ((port->fp_soft_state &
6915 6900 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6916 6901 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6917 6902 mutex_exit(&port->fp_mutex);
6918 6903 return;
6919 6904 }
6920 6905
6921 6906 if (port->fp_statec_busy == 0) {
6922 6907 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6923 6908 #ifdef DEBUG
6924 6909 } else {
6925 6910 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6926 6911 #endif
6927 6912 }
6928 6913
6929 6914 port->fp_statec_busy++;
6930 6915
6931 6916 /*
6932 6917 * For now, force the trusted method of device authentication (by
6933 6918 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6934 6919 */
6935 6920 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6936 6921 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6937 6922 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6938 6923 fp_port_offline(port, 0);
6939 6924 }
6940 6925 mutex_exit(&port->fp_mutex);
6941 6926
6942 6927 switch (FC_PORT_STATE_MASK(state)) {
6943 6928 case FC_STATE_OFFLINE:
6944 6929 job = fctl_alloc_job(JOB_PORT_OFFLINE,
6945 6930 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6946 6931 if (job == NULL) {
6947 6932 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6948 6933 " fp_statec_cb() couldn't submit a job "
6949 6934 " to the thread: failing..");
6950 6935 mutex_enter(&port->fp_mutex);
6951 6936 if (--port->fp_statec_busy == 0) {
6952 6937 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6953 6938 }
6954 6939 mutex_exit(&port->fp_mutex);
6955 6940 return;
6956 6941 }
6957 6942 mutex_enter(&port->fp_mutex);
6958 6943 /*
6959 6944 * Zero out this field so that we do not retain
6960 6945 * the fabric name as its no longer valid
6961 6946 */
6962 6947 bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6963 6948 port->fp_state = state;
6964 6949 mutex_exit(&port->fp_mutex);
6965 6950
6966 6951 fctl_enque_job(port, job);
6967 6952 break;
6968 6953
6969 6954 case FC_STATE_ONLINE:
6970 6955 case FC_STATE_LOOP:
6971 6956 mutex_enter(&port->fp_mutex);
6972 6957 port->fp_state = state;
6973 6958
6974 6959 if (port->fp_offline_tid) {
6975 6960 timeout_id_t tid;
6976 6961
6977 6962 tid = port->fp_offline_tid;
6978 6963 port->fp_offline_tid = NULL;
6979 6964 mutex_exit(&port->fp_mutex);
6980 6965 (void) untimeout(tid);
6981 6966 } else {
6982 6967 mutex_exit(&port->fp_mutex);
6983 6968 }
6984 6969
6985 6970 job = fctl_alloc_job(JOB_PORT_ONLINE,
6986 6971 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6987 6972 if (job == NULL) {
6988 6973 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6989 6974 "fp_statec_cb() couldn't submit a job "
6990 6975 "to the thread: failing..");
6991 6976
6992 6977 mutex_enter(&port->fp_mutex);
6993 6978 if (--port->fp_statec_busy == 0) {
6994 6979 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6995 6980 }
6996 6981 mutex_exit(&port->fp_mutex);
6997 6982 return;
6998 6983 }
6999 6984 fctl_enque_job(port, job);
7000 6985 break;
7001 6986
7002 6987 case FC_STATE_RESET_REQUESTED:
7003 6988 mutex_enter(&port->fp_mutex);
7004 6989 port->fp_state = FC_STATE_OFFLINE;
7005 6990 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
7006 6991 mutex_exit(&port->fp_mutex);
7007 6992 /* FALLTHROUGH */
7008 6993
7009 6994 case FC_STATE_RESET:
7010 6995 job = fctl_alloc_job(JOB_ULP_NOTIFY,
7011 6996 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
7012 6997 if (job == NULL) {
7013 6998 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
7014 6999 "fp_statec_cb() couldn't submit a job"
7015 7000 " to the thread: failing..");
7016 7001
7017 7002 mutex_enter(&port->fp_mutex);
7018 7003 if (--port->fp_statec_busy == 0) {
7019 7004 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7020 7005 }
7021 7006 mutex_exit(&port->fp_mutex);
7022 7007 return;
7023 7008 }
7024 7009
7025 7010 /* squeeze into some field in the job structure */
7026 7011 job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
7027 7012 fctl_enque_job(port, job);
7028 7013 break;
7029 7014
7030 7015 case FC_STATE_TARGET_PORT_RESET:
7031 7016 (void) fp_ulp_notify(port, state, KM_NOSLEEP);
7032 7017 /* FALLTHROUGH */
7033 7018
7034 7019 case FC_STATE_NAMESERVICE:
7035 7020 /* FALLTHROUGH */
7036 7021
7037 7022 default:
7038 7023 mutex_enter(&port->fp_mutex);
7039 7024 if (--port->fp_statec_busy == 0) {
7040 7025 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7041 7026 }
7042 7027 mutex_exit(&port->fp_mutex);
7043 7028 break;
7044 7029 }
7045 7030 }
7046 7031
7047 7032
7048 7033 /*
7049 7034 * Register with the Name Server for RSCNs
7050 7035 */
7051 7036 static int
7052 7037 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
7053 7038 int sleep)
7054 7039 {
7055 7040 uint32_t s_id;
7056 7041 uchar_t class;
7057 7042 fc_scr_req_t payload;
7058 7043 fp_cmd_t *cmd;
7059 7044 fc_packet_t *pkt;
7060 7045
7061 7046 mutex_enter(&port->fp_mutex);
7062 7047 s_id = port->fp_port_id.port_id;
7063 7048 class = port->fp_ns_login_class;
7064 7049 mutex_exit(&port->fp_mutex);
7065 7050
7066 7051 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
7067 7052 sizeof (fc_scr_resp_t), sleep, NULL);
7068 7053 if (cmd == NULL) {
7069 7054 return (FC_NOMEM);
7070 7055 }
7071 7056
7072 7057 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
7073 7058 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
7074 7059 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
7075 7060 cmd->cmd_retry_count = fp_retry_count;
7076 7061 cmd->cmd_ulp_pkt = NULL;
7077 7062
7078 7063 pkt = &cmd->cmd_pkt;
7079 7064 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
7080 7065
7081 7066 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
7082 7067
7083 7068 payload.ls_code.ls_code = LA_ELS_SCR;
7084 7069 payload.ls_code.mbz = 0;
7085 7070 payload.scr_rsvd = 0;
7086 7071 payload.scr_func = scr_func;
7087 7072
7088 7073 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
7089 7074 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
7090 7075
7091 7076 job->job_counter = 1;
7092 7077
7093 7078 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
7094 7079 fp_iodone(cmd);
7095 7080 }
7096 7081
7097 7082 return (FC_SUCCESS);
7098 7083 }
7099 7084
7100 7085
7101 7086 /*
7102 7087 * There are basically two methods to determine the total number of
7103 7088 * devices out in the NS database; Reading the details of the two
7104 7089 * methods described below, it shouldn't be hard to identify which
7105 7090 * of the two methods is better.
7106 7091 *
7107 7092 * Method 1.
7108 7093 * Iteratively issue GANs until all ports identifiers are walked
7109 7094 *
7110 7095 * Method 2.
7111 7096 * Issue GID_PT (get port Identifiers) with Maximum residual
7112 7097 * field in the request CT HEADER set to accommodate only the
7113 7098 * CT HEADER in the response frame. And if FC-GS2 has been
7114 7099 * carefully read, the NS here has a chance to FS_ACC the
7115 7100 * request and indicate the residual size in the FS_ACC.
7116 7101 *
7117 7102 * Method 2 is wonderful, although it's not mandatory for the NS
7118 7103 * to update the Maximum/Residual Field as can be seen in 4.3.1.6
7119 7104 * (note with particular care the use of the auxiliary verb 'may')
7120 7105 *
7121 7106 */
7122 7107 static int
7123 7108 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
7124 7109 int sleep)
7125 7110 {
7126 7111 int flags;
7127 7112 int rval;
7128 7113 uint32_t src_id;
7129 7114 fctl_ns_req_t *ns_cmd;
7130 7115
7131 7116 ASSERT(!MUTEX_HELD(&port->fp_mutex));
7132 7117
7133 7118 mutex_enter(&port->fp_mutex);
7134 7119 src_id = port->fp_port_id.port_id;
7135 7120 mutex_exit(&port->fp_mutex);
7136 7121
7137 7122 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7138 7123 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
7139 7124 sizeof (ns_resp_gid_pt_t), 0,
7140 7125 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
7141 7126
7142 7127 if (ns_cmd == NULL) {
7143 7128 return (FC_NOMEM);
7144 7129 }
7145 7130
7146 7131 ns_cmd->ns_cmd_code = NS_GID_PT;
7147 7132 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
7148 7133 = FC_NS_PORT_NX; /* All port types */
7149 7134 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
7150 7135
7151 7136 } else {
7152 7137 uint32_t ns_flags;
7153 7138
7154 7139 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
7155 7140 if (create) {
7156 7141 ns_flags |= FCTL_NS_CREATE_DEVICE;
7157 7142 }
7158 7143 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
7159 7144 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
7160 7145
7161 7146 if (ns_cmd == NULL) {
7162 7147 return (FC_NOMEM);
7163 7148 }
7164 7149 ns_cmd->ns_gan_index = 0;
7165 7150 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
7166 7151 ns_cmd->ns_cmd_code = NS_GA_NXT;
7167 7152 ns_cmd->ns_gan_max = 0xFFFF;
7168 7153
7169 7154 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
7170 7155 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
7171 7156 }
7172 7157
7173 7158 flags = job->job_flags;
7174 7159 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
7175 7160 job->job_counter = 1;
7176 7161
7177 7162 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
7178 7163 job->job_flags = flags;
7179 7164
7180 7165 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7181 7166 uint16_t max_resid;
7182 7167
7183 7168 /*
7184 7169 * Revert to scanning the NS if NS_GID_PT isn't
7185 7170 * helping us figure out total number of devices.
7186 7171 */
7187 7172 if (job->job_result != FC_SUCCESS ||
7188 7173 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
7189 7174 mutex_enter(&port->fp_mutex);
7190 7175 port->fp_options &= ~FP_NS_SMART_COUNT;
7191 7176 mutex_exit(&port->fp_mutex);
7192 7177
7193 7178 fctl_free_ns_cmd(ns_cmd);
7194 7179 return (fp_ns_get_devcount(port, job, create, sleep));
7195 7180 }
7196 7181
7197 7182 mutex_enter(&port->fp_mutex);
7198 7183 port->fp_total_devices = 1;
7199 7184 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7200 7185 if (max_resid) {
7201 7186 /*
7202 7187 * Since port identifier is 4 bytes and max_resid
7203 7188 * is also in WORDS, max_resid simply indicates
7204 7189 * the total number of port identifiers not
7205 7190 * transferred
7206 7191 */
7207 7192 port->fp_total_devices += max_resid;
7208 7193 }
7209 7194 mutex_exit(&port->fp_mutex);
7210 7195 }
7211 7196 mutex_enter(&port->fp_mutex);
7212 7197 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7213 7198 mutex_exit(&port->fp_mutex);
7214 7199 fctl_free_ns_cmd(ns_cmd);
7215 7200
7216 7201 return (rval);
7217 7202 }
7218 7203
7219 7204 /*
7220 7205 * One heck of a function to serve userland.
7221 7206 */
7222 7207 static int
7223 7208 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7224 7209 {
7225 7210 int rval = 0;
7226 7211 int jcode;
7227 7212 uint32_t ret;
7228 7213 uchar_t open_flag;
7229 7214 fcio_t *kfcio;
7230 7215 job_request_t *job;
7231 7216 boolean_t use32 = B_FALSE;
7232 7217
7233 7218 #ifdef _MULTI_DATAMODEL
7234 7219 switch (ddi_model_convert_from(mode & FMODELS)) {
7235 7220 case DDI_MODEL_ILP32:
7236 7221 use32 = B_TRUE;
7237 7222 break;
7238 7223
7239 7224 case DDI_MODEL_NONE:
7240 7225 default:
7241 7226 break;
7242 7227 }
7243 7228 #endif
7244 7229
7245 7230 mutex_enter(&port->fp_mutex);
7246 7231 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7247 7232 FP_SOFT_IN_UNSOL_CB)) {
7248 7233 fcio->fcio_errno = FC_STATEC_BUSY;
7249 7234 mutex_exit(&port->fp_mutex);
7250 7235 rval = EAGAIN;
7251 7236 if (fp_fcio_copyout(fcio, data, mode)) {
7252 7237 rval = EFAULT;
7253 7238 }
7254 7239 return (rval);
7255 7240 }
7256 7241 open_flag = port->fp_flag;
7257 7242 mutex_exit(&port->fp_mutex);
7258 7243
7259 7244 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7260 7245 fcio->fcio_errno = FC_FAILURE;
7261 7246 rval = EACCES;
7262 7247 if (fp_fcio_copyout(fcio, data, mode)) {
7263 7248 rval = EFAULT;
7264 7249 }
7265 7250 return (rval);
7266 7251 }
7267 7252
7268 7253 /*
7269 7254 * If an exclusive open was demanded during open, don't let
7270 7255 * either innocuous or devil threads to share the file
7271 7256 * descriptor and fire down exclusive access commands
7272 7257 */
7273 7258 mutex_enter(&port->fp_mutex);
7274 7259 if (port->fp_flag & FP_EXCL) {
7275 7260 if (port->fp_flag & FP_EXCL_BUSY) {
7276 7261 mutex_exit(&port->fp_mutex);
7277 7262 fcio->fcio_errno = FC_FAILURE;
7278 7263 return (EBUSY);
7279 7264 }
7280 7265 port->fp_flag |= FP_EXCL_BUSY;
7281 7266 }
7282 7267 mutex_exit(&port->fp_mutex);
7283 7268
7284 7269 fcio->fcio_errno = FC_SUCCESS;
7285 7270
7286 7271 switch (fcio->fcio_cmd) {
7287 7272 case FCIO_GET_HOST_PARAMS: {
7288 7273 fc_port_dev_t *val;
7289 7274 fc_port_dev32_t *val32;
7290 7275 int index;
7291 7276 int lilp_device_count;
7292 7277 fc_lilpmap_t *lilp_map;
7293 7278 uchar_t *alpa_list;
7294 7279
7295 7280 if (use32 == B_TRUE) {
7296 7281 if (fcio->fcio_olen != sizeof (*val32) ||
7297 7282 fcio->fcio_xfer != FCIO_XFER_READ) {
7298 7283 rval = EINVAL;
7299 7284 break;
7300 7285 }
7301 7286 } else {
7302 7287 if (fcio->fcio_olen != sizeof (*val) ||
7303 7288 fcio->fcio_xfer != FCIO_XFER_READ) {
7304 7289 rval = EINVAL;
7305 7290 break;
7306 7291 }
7307 7292 }
7308 7293
7309 7294 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7310 7295
7311 7296 mutex_enter(&port->fp_mutex);
7312 7297 val->dev_did = port->fp_port_id;
7313 7298 val->dev_hard_addr = port->fp_hard_addr;
7314 7299 val->dev_pwwn = port->fp_service_params.nport_ww_name;
7315 7300 val->dev_nwwn = port->fp_service_params.node_ww_name;
7316 7301 val->dev_state = port->fp_state;
7317 7302
7318 7303 lilp_map = &port->fp_lilp_map;
7319 7304 alpa_list = &lilp_map->lilp_alpalist[0];
7320 7305 lilp_device_count = lilp_map->lilp_length;
7321 7306 for (index = 0; index < lilp_device_count; index++) {
7322 7307 uint32_t d_id;
7323 7308
7324 7309 d_id = alpa_list[index];
7325 7310 if (d_id == port->fp_port_id.port_id) {
7326 7311 break;
7327 7312 }
7328 7313 }
7329 7314 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7330 7315
7331 7316 bcopy(port->fp_fc4_types, val->dev_type,
7332 7317 sizeof (port->fp_fc4_types));
7333 7318 mutex_exit(&port->fp_mutex);
7334 7319
7335 7320 if (use32 == B_TRUE) {
7336 7321 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7337 7322
7338 7323 val32->dev_did = val->dev_did;
7339 7324 val32->dev_hard_addr = val->dev_hard_addr;
7340 7325 val32->dev_pwwn = val->dev_pwwn;
7341 7326 val32->dev_nwwn = val->dev_nwwn;
7342 7327 val32->dev_state = val->dev_state;
7343 7328 val32->dev_did.priv_lilp_posit =
7344 7329 val->dev_did.priv_lilp_posit;
7345 7330
7346 7331 bcopy(val->dev_type, val32->dev_type,
7347 7332 sizeof (port->fp_fc4_types));
7348 7333
7349 7334 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7350 7335 fcio->fcio_olen, mode) == 0) {
7351 7336 if (fp_fcio_copyout(fcio, data, mode)) {
7352 7337 rval = EFAULT;
7353 7338 }
7354 7339 } else {
7355 7340 rval = EFAULT;
7356 7341 }
7357 7342
7358 7343 kmem_free(val32, sizeof (*val32));
7359 7344 } else {
7360 7345 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7361 7346 fcio->fcio_olen, mode) == 0) {
7362 7347 if (fp_fcio_copyout(fcio, data, mode)) {
7363 7348 rval = EFAULT;
7364 7349 }
7365 7350 } else {
7366 7351 rval = EFAULT;
7367 7352 }
7368 7353 }
7369 7354
7370 7355 /* need to free "val" here */
7371 7356 kmem_free(val, sizeof (*val));
7372 7357 break;
7373 7358 }
7374 7359
7375 7360 case FCIO_GET_OTHER_ADAPTER_PORTS: {
7376 7361 uint32_t index;
7377 7362 char *tmpPath;
7378 7363 fc_local_port_t *tmpPort;
7379 7364
7380 7365 if (fcio->fcio_olen < MAXPATHLEN ||
7381 7366 fcio->fcio_ilen != sizeof (uint32_t)) {
7382 7367 rval = EINVAL;
7383 7368 break;
7384 7369 }
7385 7370 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7386 7371 rval = EFAULT;
7387 7372 break;
7388 7373 }
7389 7374
7390 7375 tmpPort = fctl_get_adapter_port_by_index(port, index);
7391 7376 if (tmpPort == NULL) {
7392 7377 FP_TRACE(FP_NHEAD1(9, 0),
7393 7378 "User supplied index out of range");
7394 7379 fcio->fcio_errno = FC_BADPORT;
7395 7380 rval = EFAULT;
7396 7381 if (fp_fcio_copyout(fcio, data, mode)) {
7397 7382 rval = EFAULT;
7398 7383 }
7399 7384 break;
7400 7385 }
7401 7386
7402 7387 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7403 7388 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7404 7389 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7405 7390 MAXPATHLEN, mode) == 0) {
7406 7391 if (fp_fcio_copyout(fcio, data, mode)) {
7407 7392 rval = EFAULT;
7408 7393 }
7409 7394 } else {
7410 7395 rval = EFAULT;
7411 7396 }
7412 7397 kmem_free(tmpPath, MAXPATHLEN);
7413 7398 break;
7414 7399 }
7415 7400
7416 7401 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7417 7402 case FCIO_GET_ADAPTER_ATTRIBUTES: {
7418 7403 fc_hba_adapter_attributes_t *val;
7419 7404 fc_hba_adapter_attributes32_t *val32;
7420 7405
7421 7406 if (use32 == B_TRUE) {
7422 7407 if (fcio->fcio_olen < sizeof (*val32) ||
7423 7408 fcio->fcio_xfer != FCIO_XFER_READ) {
7424 7409 rval = EINVAL;
7425 7410 break;
7426 7411 }
7427 7412 } else {
7428 7413 if (fcio->fcio_olen < sizeof (*val) ||
7429 7414 fcio->fcio_xfer != FCIO_XFER_READ) {
7430 7415 rval = EINVAL;
7431 7416 break;
7432 7417 }
7433 7418 }
7434 7419
7435 7420 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7436 7421 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7437 7422 mutex_enter(&port->fp_mutex);
7438 7423 bcopy(port->fp_hba_port_attrs.manufacturer,
7439 7424 val->Manufacturer,
7440 7425 sizeof (val->Manufacturer));
7441 7426 bcopy(port->fp_hba_port_attrs.serial_number,
7442 7427 val->SerialNumber,
7443 7428 sizeof (val->SerialNumber));
7444 7429 bcopy(port->fp_hba_port_attrs.model,
7445 7430 val->Model,
7446 7431 sizeof (val->Model));
7447 7432 bcopy(port->fp_hba_port_attrs.model_description,
7448 7433 val->ModelDescription,
7449 7434 sizeof (val->ModelDescription));
7450 7435 bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7451 7436 port->fp_sym_node_namelen);
7452 7437 bcopy(port->fp_hba_port_attrs.hardware_version,
7453 7438 val->HardwareVersion,
7454 7439 sizeof (val->HardwareVersion));
7455 7440 bcopy(port->fp_hba_port_attrs.option_rom_version,
7456 7441 val->OptionROMVersion,
7457 7442 sizeof (val->OptionROMVersion));
7458 7443 bcopy(port->fp_hba_port_attrs.firmware_version,
7459 7444 val->FirmwareVersion,
7460 7445 sizeof (val->FirmwareVersion));
7461 7446 val->VendorSpecificID =
7462 7447 port->fp_hba_port_attrs.vendor_specific_id;
7463 7448 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7464 7449 &val->NodeWWN.raw_wwn,
7465 7450 sizeof (val->NodeWWN.raw_wwn));
7466 7451
7467 7452
7468 7453 bcopy(port->fp_hba_port_attrs.driver_name,
7469 7454 val->DriverName,
7470 7455 sizeof (val->DriverName));
7471 7456 bcopy(port->fp_hba_port_attrs.driver_version,
7472 7457 val->DriverVersion,
7473 7458 sizeof (val->DriverVersion));
7474 7459 mutex_exit(&port->fp_mutex);
7475 7460
7476 7461 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7477 7462 val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7478 7463 } else {
7479 7464 val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7480 7465 }
7481 7466
7482 7467 if (use32 == B_TRUE) {
7483 7468 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7484 7469 val32->version = val->version;
7485 7470 bcopy(val->Manufacturer, val32->Manufacturer,
7486 7471 sizeof (val->Manufacturer));
7487 7472 bcopy(val->SerialNumber, val32->SerialNumber,
7488 7473 sizeof (val->SerialNumber));
7489 7474 bcopy(val->Model, val32->Model,
7490 7475 sizeof (val->Model));
7491 7476 bcopy(val->ModelDescription, val32->ModelDescription,
7492 7477 sizeof (val->ModelDescription));
7493 7478 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7494 7479 sizeof (val->NodeSymbolicName));
7495 7480 bcopy(val->HardwareVersion, val32->HardwareVersion,
7496 7481 sizeof (val->HardwareVersion));
7497 7482 bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7498 7483 sizeof (val->OptionROMVersion));
7499 7484 bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7500 7485 sizeof (val->FirmwareVersion));
7501 7486 val32->VendorSpecificID = val->VendorSpecificID;
7502 7487 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7503 7488 sizeof (val->NodeWWN.raw_wwn));
7504 7489 bcopy(val->DriverName, val32->DriverName,
7505 7490 sizeof (val->DriverName));
7506 7491 bcopy(val->DriverVersion, val32->DriverVersion,
7507 7492 sizeof (val->DriverVersion));
7508 7493
7509 7494 val32->NumberOfPorts = val->NumberOfPorts;
7510 7495
7511 7496 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7512 7497 fcio->fcio_olen, mode) == 0) {
7513 7498 if (fp_fcio_copyout(fcio, data, mode)) {
7514 7499 rval = EFAULT;
7515 7500 }
7516 7501 } else {
7517 7502 rval = EFAULT;
7518 7503 }
7519 7504
7520 7505 kmem_free(val32, sizeof (*val32));
7521 7506 } else {
7522 7507 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7523 7508 fcio->fcio_olen, mode) == 0) {
7524 7509 if (fp_fcio_copyout(fcio, data, mode)) {
7525 7510 rval = EFAULT;
7526 7511 }
7527 7512 } else {
7528 7513 rval = EFAULT;
7529 7514 }
7530 7515 }
7531 7516
7532 7517 kmem_free(val, sizeof (*val));
7533 7518 break;
7534 7519 }
7535 7520
7536 7521 case FCIO_GET_NPIV_ATTRIBUTES: {
7537 7522 fc_hba_npiv_attributes_t *attrs;
7538 7523
7539 7524 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7540 7525 mutex_enter(&port->fp_mutex);
7541 7526 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7542 7527 &attrs->NodeWWN.raw_wwn,
7543 7528 sizeof (attrs->NodeWWN.raw_wwn));
7544 7529 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7545 7530 &attrs->PortWWN.raw_wwn,
7546 7531 sizeof (attrs->PortWWN.raw_wwn));
7547 7532 mutex_exit(&port->fp_mutex);
7548 7533 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7549 7534 fcio->fcio_olen, mode) == 0) {
7550 7535 if (fp_fcio_copyout(fcio, data, mode)) {
7551 7536 rval = EFAULT;
7552 7537 }
7553 7538 } else {
7554 7539 rval = EFAULT;
7555 7540 }
7556 7541 kmem_free(attrs, sizeof (*attrs));
7557 7542 break;
7558 7543 }
7559 7544
7560 7545 case FCIO_DELETE_NPIV_PORT: {
7561 7546 fc_local_port_t *tmpport;
7562 7547 char ww_pname[17];
7563 7548 la_wwn_t vwwn[1];
7564 7549
7565 7550 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7566 7551 if (ddi_copyin(fcio->fcio_ibuf,
7567 7552 &vwwn, sizeof (la_wwn_t), mode)) {
7568 7553 rval = EFAULT;
7569 7554 break;
7570 7555 }
7571 7556
7572 7557 fc_wwn_to_str(&vwwn[0], ww_pname);
7573 7558 FP_TRACE(FP_NHEAD1(3, 0),
7574 7559 "Delete NPIV Port %s", ww_pname);
7575 7560 tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7576 7561 if (tmpport == NULL) {
7577 7562 FP_TRACE(FP_NHEAD1(3, 0),
7578 7563 "Delete NPIV Port : no found");
7579 7564 rval = EFAULT;
7580 7565 } else {
7581 7566 fc_local_port_t *nextport = tmpport->fp_port_next;
7582 7567 fc_local_port_t *prevport = tmpport->fp_port_prev;
7583 7568 int portlen, portindex, ret;
7584 7569
7585 7570 portlen = sizeof (portindex);
7586 7571 ret = ddi_prop_op(DDI_DEV_T_ANY,
7587 7572 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7588 7573 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7589 7574 (caddr_t)&portindex, &portlen);
7590 7575 if (ret != DDI_SUCCESS) {
7591 7576 rval = EFAULT;
7592 7577 break;
7593 7578 }
7594 7579 if (ndi_devi_offline(tmpport->fp_port_dip,
7595 7580 NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7596 7581 FP_TRACE(FP_NHEAD1(1, 0),
7597 7582 "Delete NPIV Port failed");
7598 7583 mutex_enter(&port->fp_mutex);
7599 7584 tmpport->fp_npiv_state = 0;
7600 7585 mutex_exit(&port->fp_mutex);
7601 7586 rval = EFAULT;
7602 7587 } else {
7603 7588 mutex_enter(&port->fp_mutex);
7604 7589 nextport->fp_port_prev = prevport;
7605 7590 prevport->fp_port_next = nextport;
7606 7591 if (port == port->fp_port_next) {
7607 7592 port->fp_port_next =
7608 7593 port->fp_port_prev = NULL;
7609 7594 }
7610 7595 port->fp_npiv_portnum--;
7611 7596 FP_TRACE(FP_NHEAD1(3, 0),
7612 7597 "Delete NPIV Port %d", portindex);
7613 7598 port->fp_npiv_portindex[portindex-1] = 0;
7614 7599 mutex_exit(&port->fp_mutex);
7615 7600 }
7616 7601 }
7617 7602 break;
7618 7603 }
7619 7604
7620 7605 case FCIO_CREATE_NPIV_PORT: {
7621 7606 char ww_nname[17], ww_pname[17];
7622 7607 la_npiv_create_entry_t entrybuf;
7623 7608 uint32_t vportindex = 0;
7624 7609 int npiv_ret = 0;
7625 7610 char *portname, *fcaname;
7626 7611
7627 7612 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7628 7613 (void) ddi_pathname(port->fp_port_dip, portname);
7629 7614 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7630 7615 (void) ddi_pathname(port->fp_fca_dip, fcaname);
7631 7616 FP_TRACE(FP_NHEAD1(1, 0),
7632 7617 "Create NPIV port %s %s %s", portname, fcaname,
7633 7618 ddi_driver_name(port->fp_fca_dip));
7634 7619 kmem_free(portname, MAXPATHLEN);
7635 7620 kmem_free(fcaname, MAXPATHLEN);
7636 7621 if (ddi_copyin(fcio->fcio_ibuf,
7637 7622 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7638 7623 rval = EFAULT;
7639 7624 break;
7640 7625 }
7641 7626
7642 7627 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7643 7628 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7644 7629 vportindex = entrybuf.vindex;
7645 7630 FP_TRACE(FP_NHEAD1(3, 0),
7646 7631 "Create NPIV Port %s %s %d",
7647 7632 ww_nname, ww_pname, vportindex);
7648 7633
7649 7634 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7650 7635 rval = EFAULT;
7651 7636 break;
7652 7637 }
7653 7638 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7654 7639 port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7655 7640 if (npiv_ret == NDI_SUCCESS) {
7656 7641 mutex_enter(&port->fp_mutex);
7657 7642 port->fp_npiv_portnum++;
7658 7643 mutex_exit(&port->fp_mutex);
7659 7644 if (fp_copyout((void *)&vportindex,
7660 7645 (void *)fcio->fcio_obuf,
7661 7646 fcio->fcio_olen, mode) == 0) {
7662 7647 if (fp_fcio_copyout(fcio, data, mode)) {
7663 7648 rval = EFAULT;
7664 7649 }
7665 7650 } else {
7666 7651 rval = EFAULT;
7667 7652 }
7668 7653 } else {
7669 7654 rval = EFAULT;
7670 7655 }
7671 7656 FP_TRACE(FP_NHEAD1(3, 0),
7672 7657 "Create NPIV Port %d %d", npiv_ret, vportindex);
7673 7658 break;
7674 7659 }
7675 7660
7676 7661 case FCIO_GET_NPIV_PORT_LIST: {
7677 7662 fc_hba_npiv_port_list_t *list;
7678 7663 int count;
7679 7664
7680 7665 if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7681 7666 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7682 7667 rval = EINVAL;
7683 7668 break;
7684 7669 }
7685 7670
7686 7671 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7687 7672 list->version = FC_HBA_LIST_VERSION;
7688 7673
7689 7674 count = (fcio->fcio_olen -
7690 7675 (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN + 1;
7691 7676 if (port->fp_npiv_portnum > count) {
7692 7677 list->numAdapters = port->fp_npiv_portnum;
7693 7678 } else {
7694 7679 /* build npiv port list */
7695 7680 count = fc_ulp_get_npiv_port_list(port,
7696 7681 (char *)list->hbaPaths);
7697 7682 if (count < 0) {
7698 7683 rval = ENXIO;
7699 7684 FP_TRACE(FP_NHEAD1(1, 0),
7700 7685 "Build NPIV Port List error");
7701 7686 kmem_free(list, fcio->fcio_olen);
7702 7687 break;
7703 7688 }
7704 7689 list->numAdapters = count;
7705 7690 }
7706 7691
7707 7692 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7708 7693 fcio->fcio_olen, mode) == 0) {
7709 7694 if (fp_fcio_copyout(fcio, data, mode)) {
7710 7695 FP_TRACE(FP_NHEAD1(1, 0),
7711 7696 "Copy NPIV Port data error");
7712 7697 rval = EFAULT;
7713 7698 }
7714 7699 } else {
7715 7700 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7716 7701 rval = EFAULT;
7717 7702 }
7718 7703 kmem_free(list, fcio->fcio_olen);
7719 7704 break;
7720 7705 }
7721 7706
7722 7707 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7723 7708 fc_hba_port_npiv_attributes_t *val;
7724 7709
7725 7710 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7726 7711 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7727 7712
7728 7713 mutex_enter(&port->fp_mutex);
7729 7714 val->npivflag = port->fp_npiv_flag;
7730 7715 val->lastChange = port->fp_last_change;
7731 7716 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7732 7717 &val->PortWWN.raw_wwn,
7733 7718 sizeof (val->PortWWN.raw_wwn));
7734 7719 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7735 7720 &val->NodeWWN.raw_wwn,
7736 7721 sizeof (val->NodeWWN.raw_wwn));
7737 7722 mutex_exit(&port->fp_mutex);
7738 7723
7739 7724 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7740 7725 if (port->fp_npiv_type != FC_NPIV_PORT) {
7741 7726 val->MaxNumberOfNPIVPorts =
7742 7727 port->fp_fca_tran->fca_num_npivports;
7743 7728 } else {
7744 7729 val->MaxNumberOfNPIVPorts = 0;
7745 7730 }
7746 7731
7747 7732 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7748 7733 fcio->fcio_olen, mode) == 0) {
7749 7734 if (fp_fcio_copyout(fcio, data, mode)) {
7750 7735 rval = EFAULT;
7751 7736 }
7752 7737 } else {
7753 7738 rval = EFAULT;
7754 7739 }
7755 7740 kmem_free(val, sizeof (*val));
7756 7741 break;
7757 7742 }
7758 7743
7759 7744 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7760 7745 fc_hba_port_attributes_t *val;
7761 7746 fc_hba_port_attributes32_t *val32;
7762 7747
7763 7748 if (use32 == B_TRUE) {
7764 7749 if (fcio->fcio_olen < sizeof (*val32) ||
7765 7750 fcio->fcio_xfer != FCIO_XFER_READ) {
7766 7751 rval = EINVAL;
7767 7752 break;
7768 7753 }
7769 7754 } else {
7770 7755 if (fcio->fcio_olen < sizeof (*val) ||
7771 7756 fcio->fcio_xfer != FCIO_XFER_READ) {
7772 7757 rval = EINVAL;
7773 7758 break;
7774 7759 }
7775 7760 }
7776 7761
7777 7762 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7778 7763 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7779 7764 mutex_enter(&port->fp_mutex);
7780 7765 val->lastChange = port->fp_last_change;
7781 7766 val->fp_minor = port->fp_instance;
7782 7767
7783 7768 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7784 7769 &val->PortWWN.raw_wwn,
7785 7770 sizeof (val->PortWWN.raw_wwn));
7786 7771 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7787 7772 &val->NodeWWN.raw_wwn,
7788 7773 sizeof (val->NodeWWN.raw_wwn));
7789 7774 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7790 7775 sizeof (val->FabricName.raw_wwn));
7791 7776
7792 7777 val->PortFcId = port->fp_port_id.port_id;
7793 7778
7794 7779 switch (FC_PORT_STATE_MASK(port->fp_state)) {
7795 7780 case FC_STATE_OFFLINE:
7796 7781 val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7797 7782 break;
7798 7783 case FC_STATE_ONLINE:
7799 7784 case FC_STATE_LOOP:
7800 7785 case FC_STATE_NAMESERVICE:
7801 7786 val->PortState = FC_HBA_PORTSTATE_ONLINE;
7802 7787 break;
7803 7788 default:
7804 7789 val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7805 7790 break;
7806 7791 }
7807 7792
7808 7793 /* Translate from LV to FC-HBA port type codes */
7809 7794 switch (port->fp_port_type.port_type) {
7810 7795 case FC_NS_PORT_N:
7811 7796 val->PortType = FC_HBA_PORTTYPE_NPORT;
7812 7797 break;
7813 7798 case FC_NS_PORT_NL:
7814 7799 /* Actually means loop for us */
7815 7800 val->PortType = FC_HBA_PORTTYPE_LPORT;
7816 7801 break;
7817 7802 case FC_NS_PORT_F:
7818 7803 val->PortType = FC_HBA_PORTTYPE_FPORT;
7819 7804 break;
7820 7805 case FC_NS_PORT_FL:
7821 7806 val->PortType = FC_HBA_PORTTYPE_FLPORT;
7822 7807 break;
7823 7808 case FC_NS_PORT_E:
7824 7809 val->PortType = FC_HBA_PORTTYPE_EPORT;
7825 7810 break;
7826 7811 default:
7827 7812 val->PortType = FC_HBA_PORTTYPE_OTHER;
7828 7813 break;
7829 7814 }
7830 7815
7831 7816
7832 7817 /*
7833 7818 * If fp has decided that the topology is public loop,
7834 7819 * we will indicate that using the appropriate
7835 7820 * FC HBA API constant.
7836 7821 */
7837 7822 switch (port->fp_topology) {
7838 7823 case FC_TOP_PUBLIC_LOOP:
7839 7824 val->PortType = FC_HBA_PORTTYPE_NLPORT;
7840 7825 break;
7841 7826
7842 7827 case FC_TOP_PT_PT:
7843 7828 val->PortType = FC_HBA_PORTTYPE_PTP;
7844 7829 break;
7845 7830
7846 7831 case FC_TOP_UNKNOWN:
7847 7832 /*
7848 7833 * This should cover the case where nothing is connected
7849 7834 * to the port. Crystal+ is p'bly an exception here.
7850 7835 * For Crystal+, port 0 will come up as private loop
7851 7836 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7852 7837 * nothing is connected to it.
7853 7838 * Current plan is to let userland handle this.
7854 7839 */
7855 7840 if (port->fp_bind_state == FC_STATE_OFFLINE) {
7856 7841 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7857 7842 }
7858 7843 break;
7859 7844
7860 7845 default:
7861 7846 /*
7862 7847 * Do Nothing.
7863 7848 * Unused:
7864 7849 * val->PortType = FC_HBA_PORTTYPE_GPORT;
7865 7850 */
7866 7851 break;
7867 7852 }
7868 7853
7869 7854 val->PortSupportedClassofService =
7870 7855 port->fp_hba_port_attrs.supported_cos;
7871 7856 val->PortSupportedFc4Types[0] = 0;
7872 7857 bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7873 7858 sizeof (val->PortActiveFc4Types));
7874 7859 bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7875 7860 port->fp_sym_port_namelen);
7876 7861 val->PortSupportedSpeed =
7877 7862 port->fp_hba_port_attrs.supported_speed;
7878 7863
7879 7864 switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7880 7865 case FC_STATE_1GBIT_SPEED:
7881 7866 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7882 7867 break;
7883 7868 case FC_STATE_2GBIT_SPEED:
7884 7869 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7885 7870 break;
7886 7871 case FC_STATE_4GBIT_SPEED:
7887 7872 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7888 7873 break;
7889 7874 case FC_STATE_8GBIT_SPEED:
7890 7875 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7891 7876 break;
7892 7877 case FC_STATE_10GBIT_SPEED:
7893 7878 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7894 7879 break;
7895 7880 case FC_STATE_16GBIT_SPEED:
7896 7881 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7897 7882 break;
7898 7883 default:
7899 7884 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7900 7885 break;
7901 7886 }
7902 7887 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7903 7888 val->NumberofDiscoveredPorts = port->fp_dev_count;
7904 7889 mutex_exit(&port->fp_mutex);
7905 7890
7906 7891 if (use32 == B_TRUE) {
7907 7892 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7908 7893 val32->version = val->version;
7909 7894 val32->lastChange = val->lastChange;
7910 7895 val32->fp_minor = val->fp_minor;
7911 7896
7912 7897 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7913 7898 sizeof (val->PortWWN.raw_wwn));
7914 7899 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7915 7900 sizeof (val->NodeWWN.raw_wwn));
7916 7901 val32->PortFcId = val->PortFcId;
7917 7902 val32->PortState = val->PortState;
7918 7903 val32->PortType = val->PortType;
7919 7904
7920 7905 val32->PortSupportedClassofService =
7921 7906 val->PortSupportedClassofService;
7922 7907 bcopy(val->PortActiveFc4Types,
7923 7908 val32->PortActiveFc4Types,
7924 7909 sizeof (val->PortActiveFc4Types));
7925 7910 bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7926 7911 sizeof (val->PortSymbolicName));
7927 7912 bcopy(&val->FabricName, &val32->FabricName,
7928 7913 sizeof (val->FabricName.raw_wwn));
7929 7914 val32->PortSupportedSpeed = val->PortSupportedSpeed;
7930 7915 val32->PortSpeed = val->PortSpeed;
7931 7916
7932 7917 val32->PortMaxFrameSize = val->PortMaxFrameSize;
7933 7918 val32->NumberofDiscoveredPorts =
7934 7919 val->NumberofDiscoveredPorts;
7935 7920
7936 7921 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7937 7922 fcio->fcio_olen, mode) == 0) {
7938 7923 if (fp_fcio_copyout(fcio, data, mode)) {
7939 7924 rval = EFAULT;
7940 7925 }
7941 7926 } else {
7942 7927 rval = EFAULT;
7943 7928 }
7944 7929
7945 7930 kmem_free(val32, sizeof (*val32));
7946 7931 } else {
7947 7932 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7948 7933 fcio->fcio_olen, mode) == 0) {
7949 7934 if (fp_fcio_copyout(fcio, data, mode)) {
7950 7935 rval = EFAULT;
7951 7936 }
7952 7937 } else {
7953 7938 rval = EFAULT;
7954 7939 }
7955 7940 }
7956 7941
7957 7942 kmem_free(val, sizeof (*val));
7958 7943 break;
7959 7944 }
7960 7945
7961 7946 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7962 7947 fc_hba_port_attributes_t *val;
7963 7948 fc_hba_port_attributes32_t *val32;
7964 7949 uint32_t index = 0;
7965 7950 fc_remote_port_t *tmp_pd;
7966 7951
7967 7952 if (use32 == B_TRUE) {
7968 7953 if (fcio->fcio_olen < sizeof (*val32) ||
7969 7954 fcio->fcio_xfer != FCIO_XFER_READ) {
7970 7955 rval = EINVAL;
7971 7956 break;
7972 7957 }
7973 7958 } else {
7974 7959 if (fcio->fcio_olen < sizeof (*val) ||
7975 7960 fcio->fcio_xfer != FCIO_XFER_READ) {
7976 7961 rval = EINVAL;
7977 7962 break;
7978 7963 }
7979 7964 }
7980 7965
7981 7966 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7982 7967 rval = EFAULT;
7983 7968 break;
7984 7969 }
7985 7970
7986 7971 if (index >= port->fp_dev_count) {
7987 7972 FP_TRACE(FP_NHEAD1(9, 0),
7988 7973 "User supplied index out of range");
7989 7974 fcio->fcio_errno = FC_OUTOFBOUNDS;
7990 7975 rval = EINVAL;
7991 7976 if (fp_fcio_copyout(fcio, data, mode)) {
7992 7977 rval = EFAULT;
7993 7978 }
7994 7979 break;
7995 7980 }
7996 7981
7997 7982 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7998 7983 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7999 7984
8000 7985 mutex_enter(&port->fp_mutex);
8001 7986 tmp_pd = fctl_lookup_pd_by_index(port, index);
8002 7987
8003 7988 if (tmp_pd == NULL) {
8004 7989 fcio->fcio_errno = FC_BADPORT;
8005 7990 rval = EINVAL;
8006 7991 } else {
8007 7992 val->lastChange = port->fp_last_change;
8008 7993 val->fp_minor = port->fp_instance;
8009 7994
8010 7995 mutex_enter(&tmp_pd->pd_mutex);
8011 7996 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8012 7997 &val->PortWWN.raw_wwn,
8013 7998 sizeof (val->PortWWN.raw_wwn));
8014 7999 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8015 8000 &val->NodeWWN.raw_wwn,
8016 8001 sizeof (val->NodeWWN.raw_wwn));
8017 8002 val->PortFcId = tmp_pd->pd_port_id.port_id;
8018 8003 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8019 8004 tmp_pd->pd_spn_len);
8020 8005 val->PortSupportedClassofService = tmp_pd->pd_cos;
8021 8006 /*
8022 8007 * we will assume the sizeof these pd_fc4types and
8023 8008 * portActiveFc4Types will remain the same. we could
8024 8009 * add in a check for it, but we decided it was unneeded
8025 8010 */
8026 8011 bcopy((caddr_t)tmp_pd->pd_fc4types,
8027 8012 val->PortActiveFc4Types,
8028 8013 sizeof (tmp_pd->pd_fc4types));
8029 8014 val->PortState =
8030 8015 fp_map_remote_port_state(tmp_pd->pd_state);
8031 8016 mutex_exit(&tmp_pd->pd_mutex);
8032 8017
8033 8018 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8034 8019 val->PortSupportedFc4Types[0] = 0;
8035 8020 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8036 8021 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8037 8022 val->PortMaxFrameSize = 0;
8038 8023 val->NumberofDiscoveredPorts = 0;
8039 8024
8040 8025 if (use32 == B_TRUE) {
8041 8026 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8042 8027 val32->version = val->version;
8043 8028 val32->lastChange = val->lastChange;
8044 8029 val32->fp_minor = val->fp_minor;
8045 8030
8046 8031 bcopy(&val->PortWWN.raw_wwn,
8047 8032 &val32->PortWWN.raw_wwn,
8048 8033 sizeof (val->PortWWN.raw_wwn));
8049 8034 bcopy(&val->NodeWWN.raw_wwn,
8050 8035 &val32->NodeWWN.raw_wwn,
8051 8036 sizeof (val->NodeWWN.raw_wwn));
8052 8037 val32->PortFcId = val->PortFcId;
8053 8038 bcopy(val->PortSymbolicName,
8054 8039 val32->PortSymbolicName,
8055 8040 sizeof (val->PortSymbolicName));
8056 8041 val32->PortSupportedClassofService =
8057 8042 val->PortSupportedClassofService;
8058 8043 bcopy(val->PortActiveFc4Types,
8059 8044 val32->PortActiveFc4Types,
8060 8045 sizeof (tmp_pd->pd_fc4types));
8061 8046
8062 8047 val32->PortType = val->PortType;
8063 8048 val32->PortState = val->PortState;
8064 8049 val32->PortSupportedFc4Types[0] =
8065 8050 val->PortSupportedFc4Types[0];
8066 8051 val32->PortSupportedSpeed =
8067 8052 val->PortSupportedSpeed;
8068 8053 val32->PortSpeed = val->PortSpeed;
8069 8054 val32->PortMaxFrameSize =
8070 8055 val->PortMaxFrameSize;
8071 8056 val32->NumberofDiscoveredPorts =
8072 8057 val->NumberofDiscoveredPorts;
8073 8058
8074 8059 if (fp_copyout((void *)val32,
8075 8060 (void *)fcio->fcio_obuf,
8076 8061 fcio->fcio_olen, mode) == 0) {
8077 8062 if (fp_fcio_copyout(fcio,
8078 8063 data, mode)) {
8079 8064 rval = EFAULT;
8080 8065 }
8081 8066 } else {
8082 8067 rval = EFAULT;
8083 8068 }
8084 8069
8085 8070 kmem_free(val32, sizeof (*val32));
8086 8071 } else {
8087 8072 if (fp_copyout((void *)val,
8088 8073 (void *)fcio->fcio_obuf,
8089 8074 fcio->fcio_olen, mode) == 0) {
8090 8075 if (fp_fcio_copyout(fcio, data, mode)) {
8091 8076 rval = EFAULT;
8092 8077 }
8093 8078 } else {
8094 8079 rval = EFAULT;
8095 8080 }
8096 8081 }
8097 8082 }
8098 8083
8099 8084 mutex_exit(&port->fp_mutex);
8100 8085 kmem_free(val, sizeof (*val));
8101 8086 break;
8102 8087 }
8103 8088
8104 8089 case FCIO_GET_PORT_ATTRIBUTES: {
8105 8090 fc_hba_port_attributes_t *val;
8106 8091 fc_hba_port_attributes32_t *val32;
8107 8092 la_wwn_t wwn;
8108 8093 fc_remote_port_t *tmp_pd;
8109 8094
8110 8095 if (use32 == B_TRUE) {
8111 8096 if (fcio->fcio_olen < sizeof (*val32) ||
8112 8097 fcio->fcio_xfer != FCIO_XFER_READ) {
8113 8098 rval = EINVAL;
8114 8099 break;
8115 8100 }
8116 8101 } else {
8117 8102 if (fcio->fcio_olen < sizeof (*val) ||
8118 8103 fcio->fcio_xfer != FCIO_XFER_READ) {
8119 8104 rval = EINVAL;
8120 8105 break;
8121 8106 }
8122 8107 }
8123 8108
8124 8109 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8125 8110 rval = EFAULT;
8126 8111 break;
8127 8112 }
8128 8113
8129 8114 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8130 8115 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8131 8116
8132 8117 mutex_enter(&port->fp_mutex);
8133 8118 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8134 8119 val->lastChange = port->fp_last_change;
8135 8120 val->fp_minor = port->fp_instance;
8136 8121 mutex_exit(&port->fp_mutex);
8137 8122
8138 8123 if (tmp_pd == NULL) {
8139 8124 fcio->fcio_errno = FC_BADWWN;
8140 8125 rval = EINVAL;
8141 8126 } else {
8142 8127 mutex_enter(&tmp_pd->pd_mutex);
8143 8128 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8144 8129 &val->PortWWN.raw_wwn,
8145 8130 sizeof (val->PortWWN.raw_wwn));
8146 8131 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8147 8132 &val->NodeWWN.raw_wwn,
8148 8133 sizeof (val->NodeWWN.raw_wwn));
8149 8134 val->PortFcId = tmp_pd->pd_port_id.port_id;
8150 8135 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8151 8136 tmp_pd->pd_spn_len);
8152 8137 val->PortSupportedClassofService = tmp_pd->pd_cos;
8153 8138 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8154 8139 val->PortState =
8155 8140 fp_map_remote_port_state(tmp_pd->pd_state);
8156 8141 val->PortSupportedFc4Types[0] = 0;
8157 8142 /*
8158 8143 * we will assume the sizeof these pd_fc4types and
8159 8144 * portActiveFc4Types will remain the same. we could
8160 8145 * add in a check for it, but we decided it was unneeded
8161 8146 */
8162 8147 bcopy((caddr_t)tmp_pd->pd_fc4types,
8163 8148 val->PortActiveFc4Types,
8164 8149 sizeof (tmp_pd->pd_fc4types));
8165 8150 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8166 8151 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8167 8152 val->PortMaxFrameSize = 0;
8168 8153 val->NumberofDiscoveredPorts = 0;
8169 8154 mutex_exit(&tmp_pd->pd_mutex);
8170 8155
8171 8156 if (use32 == B_TRUE) {
8172 8157 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8173 8158 val32->version = val->version;
8174 8159 val32->lastChange = val->lastChange;
8175 8160 val32->fp_minor = val->fp_minor;
8176 8161 bcopy(&val->PortWWN.raw_wwn,
8177 8162 &val32->PortWWN.raw_wwn,
8178 8163 sizeof (val->PortWWN.raw_wwn));
8179 8164 bcopy(&val->NodeWWN.raw_wwn,
8180 8165 &val32->NodeWWN.raw_wwn,
8181 8166 sizeof (val->NodeWWN.raw_wwn));
8182 8167 val32->PortFcId = val->PortFcId;
8183 8168 bcopy(val->PortSymbolicName,
8184 8169 val32->PortSymbolicName,
8185 8170 sizeof (val->PortSymbolicName));
8186 8171 val32->PortSupportedClassofService =
8187 8172 val->PortSupportedClassofService;
8188 8173 val32->PortType = val->PortType;
8189 8174 val32->PortState = val->PortState;
8190 8175 val32->PortSupportedFc4Types[0] =
8191 8176 val->PortSupportedFc4Types[0];
8192 8177 bcopy(val->PortActiveFc4Types,
8193 8178 val32->PortActiveFc4Types,
8194 8179 sizeof (tmp_pd->pd_fc4types));
8195 8180 val32->PortSupportedSpeed =
8196 8181 val->PortSupportedSpeed;
8197 8182 val32->PortSpeed = val->PortSpeed;
8198 8183 val32->PortMaxFrameSize = val->PortMaxFrameSize;
8199 8184 val32->NumberofDiscoveredPorts =
8200 8185 val->NumberofDiscoveredPorts;
8201 8186
8202 8187 if (fp_copyout((void *)val32,
8203 8188 (void *)fcio->fcio_obuf,
8204 8189 fcio->fcio_olen, mode) == 0) {
8205 8190 if (fp_fcio_copyout(fcio, data, mode)) {
8206 8191 rval = EFAULT;
8207 8192 }
8208 8193 } else {
8209 8194 rval = EFAULT;
8210 8195 }
8211 8196
8212 8197 kmem_free(val32, sizeof (*val32));
8213 8198 } else {
8214 8199 if (fp_copyout((void *)val,
8215 8200 (void *)fcio->fcio_obuf,
8216 8201 fcio->fcio_olen, mode) == 0) {
8217 8202 if (fp_fcio_copyout(fcio, data, mode)) {
8218 8203 rval = EFAULT;
8219 8204 }
8220 8205 } else {
8221 8206 rval = EFAULT;
8222 8207 }
8223 8208 }
8224 8209 }
8225 8210 kmem_free(val, sizeof (*val));
8226 8211 break;
8227 8212 }
8228 8213
8229 8214 case FCIO_GET_NUM_DEVS: {
8230 8215 int num_devices;
8231 8216
8232 8217 if (fcio->fcio_olen != sizeof (num_devices) ||
8233 8218 fcio->fcio_xfer != FCIO_XFER_READ) {
8234 8219 rval = EINVAL;
8235 8220 break;
8236 8221 }
8237 8222
8238 8223 mutex_enter(&port->fp_mutex);
8239 8224 switch (port->fp_topology) {
8240 8225 case FC_TOP_PRIVATE_LOOP:
8241 8226 case FC_TOP_PT_PT:
8242 8227 num_devices = port->fp_total_devices;
8243 8228 fcio->fcio_errno = FC_SUCCESS;
8244 8229 break;
8245 8230
8246 8231 case FC_TOP_PUBLIC_LOOP:
8247 8232 case FC_TOP_FABRIC:
8248 8233 mutex_exit(&port->fp_mutex);
8249 8234 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8250 8235 NULL, KM_SLEEP);
8251 8236 ASSERT(job != NULL);
8252 8237
8253 8238 /*
8254 8239 * In FC-GS-2 the Name Server doesn't send out
8255 8240 * RSCNs for any Name Server Database updates
8256 8241 * When it is finally fixed there is no need
8257 8242 * to probe as below and should be removed.
8258 8243 */
8259 8244 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8260 8245 fctl_dealloc_job(job);
8261 8246
8262 8247 mutex_enter(&port->fp_mutex);
8263 8248 num_devices = port->fp_total_devices;
8264 8249 fcio->fcio_errno = FC_SUCCESS;
8265 8250 break;
8266 8251
8267 8252 case FC_TOP_NO_NS:
8268 8253 /* FALLTHROUGH */
8269 8254 case FC_TOP_UNKNOWN:
8270 8255 /* FALLTHROUGH */
8271 8256 default:
8272 8257 num_devices = 0;
8273 8258 fcio->fcio_errno = FC_SUCCESS;
8274 8259 break;
8275 8260 }
8276 8261 mutex_exit(&port->fp_mutex);
8277 8262
8278 8263 if (fp_copyout((void *)&num_devices,
8279 8264 (void *)fcio->fcio_obuf, fcio->fcio_olen,
8280 8265 mode) == 0) {
8281 8266 if (fp_fcio_copyout(fcio, data, mode)) {
8282 8267 rval = EFAULT;
8283 8268 }
8284 8269 } else {
8285 8270 rval = EFAULT;
8286 8271 }
8287 8272 break;
8288 8273 }
8289 8274
8290 8275 case FCIO_GET_DEV_LIST: {
8291 8276 int num_devices;
8292 8277 int new_count;
8293 8278 int map_size;
8294 8279
8295 8280 if (fcio->fcio_xfer != FCIO_XFER_READ ||
8296 8281 fcio->fcio_alen != sizeof (new_count)) {
8297 8282 rval = EINVAL;
8298 8283 break;
8299 8284 }
8300 8285
8301 8286 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8302 8287
8303 8288 mutex_enter(&port->fp_mutex);
8304 8289 if (num_devices < port->fp_total_devices) {
8305 8290 fcio->fcio_errno = FC_TOOMANY;
8306 8291 new_count = port->fp_total_devices;
8307 8292 mutex_exit(&port->fp_mutex);
8308 8293
8309 8294 if (fp_copyout((void *)&new_count,
8310 8295 (void *)fcio->fcio_abuf,
8311 8296 sizeof (new_count), mode)) {
8312 8297 rval = EFAULT;
8313 8298 break;
8314 8299 }
8315 8300
8316 8301 if (fp_fcio_copyout(fcio, data, mode)) {
8317 8302 rval = EFAULT;
8318 8303 break;
8319 8304 }
8320 8305 rval = EINVAL;
8321 8306 break;
8322 8307 }
8323 8308
8324 8309 if (port->fp_total_devices <= 0) {
8325 8310 fcio->fcio_errno = FC_NO_MAP;
8326 8311 new_count = port->fp_total_devices;
8327 8312 mutex_exit(&port->fp_mutex);
8328 8313
8329 8314 if (fp_copyout((void *)&new_count,
8330 8315 (void *)fcio->fcio_abuf,
8331 8316 sizeof (new_count), mode)) {
8332 8317 rval = EFAULT;
8333 8318 break;
8334 8319 }
8335 8320
8336 8321 if (fp_fcio_copyout(fcio, data, mode)) {
8337 8322 rval = EFAULT;
8338 8323 break;
8339 8324 }
8340 8325 rval = EINVAL;
8341 8326 break;
8342 8327 }
8343 8328
8344 8329 switch (port->fp_topology) {
8345 8330 case FC_TOP_PRIVATE_LOOP:
8346 8331 if (fp_fillout_loopmap(port, fcio,
8347 8332 mode) != FC_SUCCESS) {
8348 8333 rval = EFAULT;
8349 8334 break;
8350 8335 }
8351 8336 if (fp_fcio_copyout(fcio, data, mode)) {
8352 8337 rval = EFAULT;
8353 8338 }
8354 8339 break;
8355 8340
8356 8341 case FC_TOP_PT_PT:
8357 8342 if (fp_fillout_p2pmap(port, fcio,
8358 8343 mode) != FC_SUCCESS) {
8359 8344 rval = EFAULT;
8360 8345 break;
8361 8346 }
8362 8347 if (fp_fcio_copyout(fcio, data, mode)) {
8363 8348 rval = EFAULT;
8364 8349 }
8365 8350 break;
8366 8351
8367 8352 case FC_TOP_PUBLIC_LOOP:
8368 8353 case FC_TOP_FABRIC: {
8369 8354 fctl_ns_req_t *ns_cmd;
8370 8355
8371 8356 map_size =
8372 8357 sizeof (fc_port_dev_t) * port->fp_total_devices;
8373 8358
8374 8359 mutex_exit(&port->fp_mutex);
8375 8360
8376 8361 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8377 8362 sizeof (ns_resp_gan_t), map_size,
8378 8363 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8379 8364 KM_SLEEP);
8380 8365 ASSERT(ns_cmd != NULL);
8381 8366
8382 8367 ns_cmd->ns_gan_index = 0;
8383 8368 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8384 8369 ns_cmd->ns_cmd_code = NS_GA_NXT;
8385 8370 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8386 8371
8387 8372 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8388 8373 NULL, KM_SLEEP);
8389 8374 ASSERT(job != NULL);
8390 8375
8391 8376 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8392 8377
8393 8378 if (ret != FC_SUCCESS ||
8394 8379 job->job_result != FC_SUCCESS) {
8395 8380 fctl_free_ns_cmd(ns_cmd);
8396 8381
8397 8382 fcio->fcio_errno = job->job_result;
8398 8383 new_count = 0;
8399 8384 if (fp_copyout((void *)&new_count,
8400 8385 (void *)fcio->fcio_abuf,
8401 8386 sizeof (new_count), mode)) {
8402 8387 fctl_dealloc_job(job);
8403 8388 mutex_enter(&port->fp_mutex);
8404 8389 rval = EFAULT;
8405 8390 break;
8406 8391 }
8407 8392
8408 8393 if (fp_fcio_copyout(fcio, data, mode)) {
8409 8394 fctl_dealloc_job(job);
8410 8395 mutex_enter(&port->fp_mutex);
8411 8396 rval = EFAULT;
8412 8397 break;
8413 8398 }
8414 8399 rval = EIO;
8415 8400 mutex_enter(&port->fp_mutex);
8416 8401 break;
8417 8402 }
8418 8403 fctl_dealloc_job(job);
8419 8404
8420 8405 new_count = ns_cmd->ns_gan_index;
8421 8406 if (fp_copyout((void *)&new_count,
8422 8407 (void *)fcio->fcio_abuf, sizeof (new_count),
8423 8408 mode)) {
8424 8409 rval = EFAULT;
8425 8410 fctl_free_ns_cmd(ns_cmd);
8426 8411 mutex_enter(&port->fp_mutex);
8427 8412 break;
8428 8413 }
8429 8414
8430 8415 if (fp_copyout((void *)ns_cmd->ns_data_buf,
8431 8416 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8432 8417 ns_cmd->ns_gan_index, mode)) {
8433 8418 rval = EFAULT;
8434 8419 fctl_free_ns_cmd(ns_cmd);
8435 8420 mutex_enter(&port->fp_mutex);
8436 8421 break;
8437 8422 }
8438 8423 fctl_free_ns_cmd(ns_cmd);
8439 8424
8440 8425 if (fp_fcio_copyout(fcio, data, mode)) {
8441 8426 rval = EFAULT;
8442 8427 }
8443 8428 mutex_enter(&port->fp_mutex);
8444 8429 break;
8445 8430 }
8446 8431
8447 8432 case FC_TOP_NO_NS:
8448 8433 /* FALLTHROUGH */
8449 8434 case FC_TOP_UNKNOWN:
8450 8435 /* FALLTHROUGH */
8451 8436 default:
8452 8437 fcio->fcio_errno = FC_NO_MAP;
8453 8438 num_devices = port->fp_total_devices;
8454 8439
8455 8440 if (fp_copyout((void *)&new_count,
8456 8441 (void *)fcio->fcio_abuf,
8457 8442 sizeof (new_count), mode)) {
8458 8443 rval = EFAULT;
8459 8444 break;
8460 8445 }
8461 8446
8462 8447 if (fp_fcio_copyout(fcio, data, mode)) {
8463 8448 rval = EFAULT;
8464 8449 break;
8465 8450 }
8466 8451 rval = EINVAL;
8467 8452 break;
8468 8453 }
8469 8454 mutex_exit(&port->fp_mutex);
8470 8455 break;
8471 8456 }
8472 8457
8473 8458 case FCIO_GET_SYM_PNAME: {
8474 8459 rval = ENOTSUP;
8475 8460 break;
8476 8461 }
8477 8462
8478 8463 case FCIO_GET_SYM_NNAME: {
8479 8464 rval = ENOTSUP;
8480 8465 break;
8481 8466 }
8482 8467
8483 8468 case FCIO_SET_SYM_PNAME: {
8484 8469 rval = ENOTSUP;
8485 8470 break;
8486 8471 }
8487 8472
8488 8473 case FCIO_SET_SYM_NNAME: {
8489 8474 rval = ENOTSUP;
8490 8475 break;
8491 8476 }
8492 8477
8493 8478 case FCIO_GET_LOGI_PARAMS: {
8494 8479 la_wwn_t pwwn;
8495 8480 la_wwn_t *my_pwwn;
8496 8481 la_els_logi_t *params;
8497 8482 la_els_logi32_t *params32;
8498 8483 fc_remote_node_t *node;
8499 8484 fc_remote_port_t *pd;
8500 8485
8501 8486 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8502 8487 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8503 8488 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8504 8489 rval = EINVAL;
8505 8490 break;
8506 8491 }
8507 8492
8508 8493 if (use32 == B_TRUE) {
8509 8494 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8510 8495 rval = EINVAL;
8511 8496 break;
8512 8497 }
8513 8498 } else {
8514 8499 if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8515 8500 rval = EINVAL;
8516 8501 break;
8517 8502 }
8518 8503 }
8519 8504
8520 8505 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8521 8506 rval = EFAULT;
8522 8507 break;
8523 8508 }
8524 8509
8525 8510 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8526 8511 if (pd == NULL) {
8527 8512 mutex_enter(&port->fp_mutex);
8528 8513 my_pwwn = &port->fp_service_params.nport_ww_name;
8529 8514 mutex_exit(&port->fp_mutex);
8530 8515
8531 8516 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8532 8517 rval = ENXIO;
8533 8518 break;
8534 8519 }
8535 8520
8536 8521 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8537 8522 mutex_enter(&port->fp_mutex);
8538 8523 *params = port->fp_service_params;
8539 8524 mutex_exit(&port->fp_mutex);
8540 8525 } else {
8541 8526 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8542 8527
8543 8528 mutex_enter(&pd->pd_mutex);
8544 8529 params->ls_code.mbz = params->ls_code.ls_code = 0;
8545 8530 params->common_service = pd->pd_csp;
8546 8531 params->nport_ww_name = pd->pd_port_name;
8547 8532 params->class_1 = pd->pd_clsp1;
8548 8533 params->class_2 = pd->pd_clsp2;
8549 8534 params->class_3 = pd->pd_clsp3;
8550 8535 node = pd->pd_remote_nodep;
8551 8536 mutex_exit(&pd->pd_mutex);
8552 8537
8553 8538 bzero(params->reserved, sizeof (params->reserved));
8554 8539
8555 8540 mutex_enter(&node->fd_mutex);
8556 8541 bcopy(node->fd_vv, params->vendor_version,
8557 8542 sizeof (node->fd_vv));
8558 8543 params->node_ww_name = node->fd_node_name;
8559 8544 mutex_exit(&node->fd_mutex);
8560 8545
8561 8546 fctl_release_remote_port(pd);
8562 8547 }
8563 8548
8564 8549 if (use32 == B_TRUE) {
8565 8550 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8566 8551
8567 8552 params32->ls_code.mbz = params->ls_code.mbz;
8568 8553 params32->common_service = params->common_service;
8569 8554 params32->nport_ww_name = params->nport_ww_name;
8570 8555 params32->class_1 = params->class_1;
8571 8556 params32->class_2 = params->class_2;
8572 8557 params32->class_3 = params->class_3;
8573 8558 bzero(params32->reserved, sizeof (params32->reserved));
8574 8559 bcopy(params->vendor_version, params32->vendor_version,
8575 8560 sizeof (node->fd_vv));
8576 8561 params32->node_ww_name = params->node_ww_name;
8577 8562
8578 8563 if (ddi_copyout((void *)params32,
8579 8564 (void *)fcio->fcio_obuf,
8580 8565 sizeof (*params32), mode)) {
8581 8566 rval = EFAULT;
8582 8567 }
8583 8568
8584 8569 kmem_free(params32, sizeof (*params32));
8585 8570 } else {
8586 8571 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8587 8572 sizeof (*params), mode)) {
8588 8573 rval = EFAULT;
8589 8574 }
8590 8575 }
8591 8576
8592 8577 kmem_free(params, sizeof (*params));
8593 8578 if (fp_fcio_copyout(fcio, data, mode)) {
8594 8579 rval = EFAULT;
8595 8580 }
8596 8581 break;
8597 8582 }
8598 8583
8599 8584 case FCIO_DEV_LOGOUT:
8600 8585 case FCIO_DEV_LOGIN:
8601 8586 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8602 8587 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8603 8588 rval = EINVAL;
8604 8589
8605 8590 if (fp_fcio_copyout(fcio, data, mode)) {
8606 8591 rval = EFAULT;
8607 8592 }
8608 8593 break;
8609 8594 }
8610 8595
8611 8596 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8612 8597 jcode = JOB_FCIO_LOGIN;
8613 8598 } else {
8614 8599 jcode = JOB_FCIO_LOGOUT;
8615 8600 }
8616 8601
8617 8602 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8618 8603 bcopy(fcio, kfcio, sizeof (*fcio));
8619 8604
8620 8605 if (kfcio->fcio_ilen) {
8621 8606 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8622 8607 KM_SLEEP);
8623 8608
8624 8609 if (ddi_copyin((void *)fcio->fcio_ibuf,
8625 8610 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8626 8611 mode)) {
8627 8612 rval = EFAULT;
8628 8613
8629 8614 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8630 8615 kmem_free(kfcio, sizeof (*kfcio));
8631 8616 fcio->fcio_errno = job->job_result;
8632 8617 if (fp_fcio_copyout(fcio, data, mode)) {
8633 8618 rval = EFAULT;
8634 8619 }
8635 8620 break;
8636 8621 }
8637 8622 }
8638 8623
8639 8624 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8640 8625 job->job_private = kfcio;
8641 8626
8642 8627 fctl_enque_job(port, job);
8643 8628 fctl_jobwait(job);
8644 8629
8645 8630 rval = job->job_result;
8646 8631
8647 8632 fcio->fcio_errno = kfcio->fcio_errno;
8648 8633 if (fp_fcio_copyout(fcio, data, mode)) {
8649 8634 rval = EFAULT;
8650 8635 }
8651 8636
8652 8637 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8653 8638 kmem_free(kfcio, sizeof (*kfcio));
8654 8639 fctl_dealloc_job(job);
8655 8640 break;
8656 8641
8657 8642 case FCIO_GET_STATE: {
8658 8643 la_wwn_t pwwn;
8659 8644 uint32_t state;
8660 8645 fc_remote_port_t *pd;
8661 8646 fctl_ns_req_t *ns_cmd;
8662 8647
8663 8648 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8664 8649 fcio->fcio_olen != sizeof (state) ||
8665 8650 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8666 8651 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8667 8652 rval = EINVAL;
8668 8653 break;
8669 8654 }
8670 8655
8671 8656 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8672 8657 rval = EFAULT;
8673 8658 break;
8674 8659 }
8675 8660 fcio->fcio_errno = 0;
8676 8661
8677 8662 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8678 8663 if (pd == NULL) {
8679 8664 mutex_enter(&port->fp_mutex);
8680 8665 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8681 8666 mutex_exit(&port->fp_mutex);
8682 8667 job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8683 8668 NULL, NULL, KM_SLEEP);
8684 8669
8685 8670 job->job_counter = 1;
8686 8671 job->job_result = FC_SUCCESS;
8687 8672
8688 8673 ns_cmd = fctl_alloc_ns_cmd(
8689 8674 sizeof (ns_req_gid_pn_t),
8690 8675 sizeof (ns_resp_gid_pn_t),
8691 8676 sizeof (ns_resp_gid_pn_t),
8692 8677 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8693 8678 ASSERT(ns_cmd != NULL);
8694 8679
8695 8680 ns_cmd->ns_cmd_code = NS_GID_PN;
8696 8681 ((ns_req_gid_pn_t *)
8697 8682 (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8698 8683
8699 8684 ret = fp_ns_query(port, ns_cmd, job,
8700 8685 1, KM_SLEEP);
8701 8686
8702 8687 if (ret != FC_SUCCESS || job->job_result !=
8703 8688 FC_SUCCESS) {
8704 8689 if (ret != FC_SUCCESS) {
8705 8690 fcio->fcio_errno = ret;
8706 8691 } else {
8707 8692 fcio->fcio_errno =
8708 8693 job->job_result;
8709 8694 }
8710 8695 rval = EIO;
8711 8696 } else {
8712 8697 state = PORT_DEVICE_INVALID;
8713 8698 }
8714 8699 fctl_free_ns_cmd(ns_cmd);
8715 8700 fctl_dealloc_job(job);
8716 8701 } else {
8717 8702 mutex_exit(&port->fp_mutex);
8718 8703 fcio->fcio_errno = FC_BADWWN;
8719 8704 rval = ENXIO;
8720 8705 }
8721 8706 } else {
8722 8707 mutex_enter(&pd->pd_mutex);
8723 8708 state = pd->pd_state;
8724 8709 mutex_exit(&pd->pd_mutex);
8725 8710
8726 8711 fctl_release_remote_port(pd);
8727 8712 }
8728 8713
8729 8714 if (!rval) {
8730 8715 if (ddi_copyout((void *)&state,
8731 8716 (void *)fcio->fcio_obuf, sizeof (state),
8732 8717 mode)) {
8733 8718 rval = EFAULT;
8734 8719 }
8735 8720 }
8736 8721 if (fp_fcio_copyout(fcio, data, mode)) {
8737 8722 rval = EFAULT;
8738 8723 }
8739 8724 break;
8740 8725 }
8741 8726
8742 8727 case FCIO_DEV_REMOVE: {
8743 8728 la_wwn_t pwwn;
8744 8729 fc_portmap_t *changelist;
8745 8730 fc_remote_port_t *pd;
8746 8731
8747 8732 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8748 8733 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8749 8734 rval = EINVAL;
8750 8735 break;
8751 8736 }
8752 8737
8753 8738 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8754 8739 rval = EFAULT;
8755 8740 break;
8756 8741 }
8757 8742
8758 8743 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8759 8744 if (pd == NULL) {
8760 8745 rval = ENXIO;
8761 8746 fcio->fcio_errno = FC_BADWWN;
8762 8747 if (fp_fcio_copyout(fcio, data, mode)) {
8763 8748 rval = EFAULT;
8764 8749 }
8765 8750 break;
8766 8751 }
8767 8752
8768 8753 mutex_enter(&pd->pd_mutex);
8769 8754 if (pd->pd_ref_count > 1) {
8770 8755 mutex_exit(&pd->pd_mutex);
8771 8756
8772 8757 rval = EBUSY;
8773 8758 fcio->fcio_errno = FC_FAILURE;
8774 8759 fctl_release_remote_port(pd);
8775 8760
8776 8761 if (fp_fcio_copyout(fcio, data, mode)) {
8777 8762 rval = EFAULT;
8778 8763 }
8779 8764 break;
8780 8765 }
8781 8766 mutex_exit(&pd->pd_mutex);
8782 8767
8783 8768 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8784 8769
8785 8770 fctl_copy_portmap(changelist, pd);
8786 8771 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8787 8772 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8788 8773
8789 8774 fctl_release_remote_port(pd);
8790 8775 break;
8791 8776 }
8792 8777
8793 8778 case FCIO_GET_FCODE_REV: {
8794 8779 caddr_t fcode_rev;
8795 8780 fc_fca_pm_t pm;
8796 8781
8797 8782 if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8798 8783 fcio->fcio_xfer != FCIO_XFER_READ) {
8799 8784 rval = EINVAL;
8800 8785 break;
8801 8786 }
8802 8787 bzero((caddr_t)&pm, sizeof (pm));
8803 8788
8804 8789 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8805 8790
8806 8791 pm.pm_cmd_flags = FC_FCA_PM_READ;
8807 8792 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8808 8793 pm.pm_data_len = fcio->fcio_olen;
8809 8794 pm.pm_data_buf = fcode_rev;
8810 8795
8811 8796 ret = port->fp_fca_tran->fca_port_manage(
8812 8797 port->fp_fca_handle, &pm);
8813 8798
8814 8799 if (ret == FC_SUCCESS) {
8815 8800 if (ddi_copyout((void *)fcode_rev,
8816 8801 (void *)fcio->fcio_obuf,
8817 8802 fcio->fcio_olen, mode) == 0) {
8818 8803 if (fp_fcio_copyout(fcio, data, mode)) {
8819 8804 rval = EFAULT;
8820 8805 }
8821 8806 } else {
8822 8807 rval = EFAULT;
8823 8808 }
8824 8809 } else {
8825 8810 /*
8826 8811 * check if buffer was not large enough to obtain
8827 8812 * FCODE version.
8828 8813 */
8829 8814 if (pm.pm_data_len > fcio->fcio_olen) {
8830 8815 rval = ENOMEM;
8831 8816 } else {
8832 8817 rval = EIO;
8833 8818 }
8834 8819 fcio->fcio_errno = ret;
8835 8820 if (fp_fcio_copyout(fcio, data, mode)) {
8836 8821 rval = EFAULT;
8837 8822 }
8838 8823 }
8839 8824 kmem_free(fcode_rev, fcio->fcio_olen);
8840 8825 break;
8841 8826 }
8842 8827
8843 8828 case FCIO_GET_FW_REV: {
8844 8829 caddr_t fw_rev;
8845 8830 fc_fca_pm_t pm;
8846 8831
8847 8832 if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8848 8833 fcio->fcio_xfer != FCIO_XFER_READ) {
8849 8834 rval = EINVAL;
8850 8835 break;
8851 8836 }
8852 8837 bzero((caddr_t)&pm, sizeof (pm));
8853 8838
8854 8839 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8855 8840
8856 8841 pm.pm_cmd_flags = FC_FCA_PM_READ;
8857 8842 pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8858 8843 pm.pm_data_len = fcio->fcio_olen;
8859 8844 pm.pm_data_buf = fw_rev;
8860 8845
8861 8846 ret = port->fp_fca_tran->fca_port_manage(
8862 8847 port->fp_fca_handle, &pm);
8863 8848
8864 8849 if (ret == FC_SUCCESS) {
8865 8850 if (ddi_copyout((void *)fw_rev,
8866 8851 (void *)fcio->fcio_obuf,
8867 8852 fcio->fcio_olen, mode) == 0) {
8868 8853 if (fp_fcio_copyout(fcio, data, mode)) {
8869 8854 rval = EFAULT;
8870 8855 }
8871 8856 } else {
8872 8857 rval = EFAULT;
8873 8858 }
8874 8859 } else {
8875 8860 if (fp_fcio_copyout(fcio, data, mode)) {
8876 8861 rval = EFAULT;
8877 8862 }
8878 8863 rval = EIO;
8879 8864 }
8880 8865 kmem_free(fw_rev, fcio->fcio_olen);
8881 8866 break;
8882 8867 }
8883 8868
8884 8869 case FCIO_GET_DUMP_SIZE: {
8885 8870 uint32_t dump_size;
8886 8871 fc_fca_pm_t pm;
8887 8872
8888 8873 if (fcio->fcio_olen != sizeof (dump_size) ||
8889 8874 fcio->fcio_xfer != FCIO_XFER_READ) {
8890 8875 rval = EINVAL;
8891 8876 break;
8892 8877 }
8893 8878 bzero((caddr_t)&pm, sizeof (pm));
8894 8879 pm.pm_cmd_flags = FC_FCA_PM_READ;
8895 8880 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8896 8881 pm.pm_data_len = sizeof (dump_size);
8897 8882 pm.pm_data_buf = (caddr_t)&dump_size;
8898 8883
8899 8884 ret = port->fp_fca_tran->fca_port_manage(
8900 8885 port->fp_fca_handle, &pm);
8901 8886
8902 8887 if (ret == FC_SUCCESS) {
8903 8888 if (ddi_copyout((void *)&dump_size,
8904 8889 (void *)fcio->fcio_obuf, sizeof (dump_size),
8905 8890 mode) == 0) {
8906 8891 if (fp_fcio_copyout(fcio, data, mode)) {
8907 8892 rval = EFAULT;
8908 8893 }
8909 8894 } else {
8910 8895 rval = EFAULT;
8911 8896 }
8912 8897 } else {
8913 8898 fcio->fcio_errno = ret;
8914 8899 rval = EIO;
8915 8900 if (fp_fcio_copyout(fcio, data, mode)) {
8916 8901 rval = EFAULT;
8917 8902 }
8918 8903 }
8919 8904 break;
8920 8905 }
8921 8906
8922 8907 case FCIO_DOWNLOAD_FW: {
8923 8908 caddr_t firmware;
8924 8909 fc_fca_pm_t pm;
8925 8910
8926 8911 if (fcio->fcio_ilen <= 0 ||
8927 8912 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8928 8913 rval = EINVAL;
8929 8914 break;
8930 8915 }
8931 8916
8932 8917 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8933 8918 if (ddi_copyin(fcio->fcio_ibuf, firmware,
8934 8919 fcio->fcio_ilen, mode)) {
8935 8920 rval = EFAULT;
8936 8921 kmem_free(firmware, fcio->fcio_ilen);
8937 8922 break;
8938 8923 }
8939 8924
8940 8925 bzero((caddr_t)&pm, sizeof (pm));
8941 8926 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8942 8927 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8943 8928 pm.pm_data_len = fcio->fcio_ilen;
8944 8929 pm.pm_data_buf = firmware;
8945 8930
8946 8931 ret = port->fp_fca_tran->fca_port_manage(
8947 8932 port->fp_fca_handle, &pm);
8948 8933
8949 8934 kmem_free(firmware, fcio->fcio_ilen);
8950 8935
8951 8936 if (ret != FC_SUCCESS) {
8952 8937 fcio->fcio_errno = ret;
8953 8938 rval = EIO;
8954 8939 if (fp_fcio_copyout(fcio, data, mode)) {
8955 8940 rval = EFAULT;
8956 8941 }
8957 8942 }
8958 8943 break;
8959 8944 }
8960 8945
8961 8946 case FCIO_DOWNLOAD_FCODE: {
8962 8947 caddr_t fcode;
8963 8948 fc_fca_pm_t pm;
8964 8949
8965 8950 if (fcio->fcio_ilen <= 0 ||
8966 8951 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8967 8952 rval = EINVAL;
8968 8953 break;
8969 8954 }
8970 8955
8971 8956 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8972 8957 if (ddi_copyin(fcio->fcio_ibuf, fcode,
8973 8958 fcio->fcio_ilen, mode)) {
8974 8959 rval = EFAULT;
8975 8960 kmem_free(fcode, fcio->fcio_ilen);
8976 8961 break;
8977 8962 }
8978 8963
8979 8964 bzero((caddr_t)&pm, sizeof (pm));
8980 8965 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8981 8966 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8982 8967 pm.pm_data_len = fcio->fcio_ilen;
8983 8968 pm.pm_data_buf = fcode;
8984 8969
8985 8970 ret = port->fp_fca_tran->fca_port_manage(
8986 8971 port->fp_fca_handle, &pm);
8987 8972
8988 8973 kmem_free(fcode, fcio->fcio_ilen);
8989 8974
8990 8975 if (ret != FC_SUCCESS) {
8991 8976 fcio->fcio_errno = ret;
8992 8977 rval = EIO;
8993 8978 if (fp_fcio_copyout(fcio, data, mode)) {
8994 8979 rval = EFAULT;
8995 8980 }
8996 8981 }
8997 8982 break;
8998 8983 }
8999 8984
9000 8985 case FCIO_FORCE_DUMP:
9001 8986 ret = port->fp_fca_tran->fca_reset(
9002 8987 port->fp_fca_handle, FC_FCA_CORE);
9003 8988
9004 8989 if (ret != FC_SUCCESS) {
9005 8990 fcio->fcio_errno = ret;
9006 8991 rval = EIO;
9007 8992 if (fp_fcio_copyout(fcio, data, mode)) {
9008 8993 rval = EFAULT;
9009 8994 }
9010 8995 }
9011 8996 break;
9012 8997
9013 8998 case FCIO_GET_DUMP: {
9014 8999 caddr_t dump;
9015 9000 uint32_t dump_size;
9016 9001 fc_fca_pm_t pm;
9017 9002
9018 9003 if (fcio->fcio_xfer != FCIO_XFER_READ) {
9019 9004 rval = EINVAL;
9020 9005 break;
9021 9006 }
9022 9007 bzero((caddr_t)&pm, sizeof (pm));
9023 9008
9024 9009 pm.pm_cmd_flags = FC_FCA_PM_READ;
9025 9010 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
9026 9011 pm.pm_data_len = sizeof (dump_size);
9027 9012 pm.pm_data_buf = (caddr_t)&dump_size;
9028 9013
9029 9014 ret = port->fp_fca_tran->fca_port_manage(
9030 9015 port->fp_fca_handle, &pm);
9031 9016
9032 9017 if (ret != FC_SUCCESS) {
9033 9018 fcio->fcio_errno = ret;
9034 9019 rval = EIO;
9035 9020 if (fp_fcio_copyout(fcio, data, mode)) {
9036 9021 rval = EFAULT;
9037 9022 }
9038 9023 break;
9039 9024 }
9040 9025 if (fcio->fcio_olen != dump_size) {
9041 9026 fcio->fcio_errno = FC_NOMEM;
9042 9027 rval = EINVAL;
9043 9028 if (fp_fcio_copyout(fcio, data, mode)) {
9044 9029 rval = EFAULT;
9045 9030 }
9046 9031 break;
9047 9032 }
9048 9033
9049 9034 dump = kmem_zalloc(dump_size, KM_SLEEP);
9050 9035
9051 9036 bzero((caddr_t)&pm, sizeof (pm));
9052 9037 pm.pm_cmd_flags = FC_FCA_PM_READ;
9053 9038 pm.pm_cmd_code = FC_PORT_GET_DUMP;
9054 9039 pm.pm_data_len = dump_size;
9055 9040 pm.pm_data_buf = dump;
9056 9041
9057 9042 ret = port->fp_fca_tran->fca_port_manage(
9058 9043 port->fp_fca_handle, &pm);
9059 9044
9060 9045 if (ret == FC_SUCCESS) {
9061 9046 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
9062 9047 dump_size, mode) == 0) {
9063 9048 if (fp_fcio_copyout(fcio, data, mode)) {
9064 9049 rval = EFAULT;
9065 9050 }
9066 9051 } else {
9067 9052 rval = EFAULT;
9068 9053 }
9069 9054 } else {
9070 9055 fcio->fcio_errno = ret;
9071 9056 rval = EIO;
9072 9057 if (fp_fcio_copyout(fcio, data, mode)) {
9073 9058 rval = EFAULT;
9074 9059 }
9075 9060 }
9076 9061 kmem_free(dump, dump_size);
9077 9062 break;
9078 9063 }
9079 9064
9080 9065 case FCIO_GET_TOPOLOGY: {
9081 9066 uint32_t user_topology;
9082 9067
9083 9068 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9084 9069 fcio->fcio_olen != sizeof (user_topology)) {
9085 9070 rval = EINVAL;
9086 9071 break;
9087 9072 }
9088 9073
9089 9074 mutex_enter(&port->fp_mutex);
9090 9075 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9091 9076 user_topology = FC_TOP_UNKNOWN;
9092 9077 } else {
9093 9078 user_topology = port->fp_topology;
9094 9079 }
9095 9080 mutex_exit(&port->fp_mutex);
9096 9081
9097 9082 if (ddi_copyout((void *)&user_topology,
9098 9083 (void *)fcio->fcio_obuf, sizeof (user_topology),
9099 9084 mode)) {
9100 9085 rval = EFAULT;
9101 9086 }
9102 9087 break;
9103 9088 }
9104 9089
9105 9090 case FCIO_RESET_LINK: {
9106 9091 la_wwn_t pwwn;
9107 9092
9108 9093 /*
9109 9094 * Look at the output buffer field; if this field has zero
9110 9095 * bytes then attempt to reset the local link/loop. If the
9111 9096 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9112 9097 * and if yes, determine the LFA and reset the remote LIP
9113 9098 * by LINIT ELS.
9114 9099 */
9115 9100
9116 9101 if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9117 9102 fcio->fcio_ilen != sizeof (pwwn)) {
9118 9103 rval = EINVAL;
9119 9104 break;
9120 9105 }
9121 9106
9122 9107 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9123 9108 sizeof (pwwn), mode)) {
9124 9109 rval = EFAULT;
9125 9110 break;
9126 9111 }
9127 9112
9128 9113 mutex_enter(&port->fp_mutex);
9129 9114 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9130 9115 mutex_exit(&port->fp_mutex);
9131 9116 break;
9132 9117 }
9133 9118 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9134 9119 mutex_exit(&port->fp_mutex);
9135 9120
9136 9121 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9137 9122 if (job == NULL) {
9138 9123 rval = ENOMEM;
9139 9124 break;
9140 9125 }
9141 9126 job->job_counter = 1;
9142 9127 job->job_private = (void *)&pwwn;
9143 9128
9144 9129 fctl_enque_job(port, job);
9145 9130 fctl_jobwait(job);
9146 9131
9147 9132 mutex_enter(&port->fp_mutex);
9148 9133 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9149 9134 mutex_exit(&port->fp_mutex);
9150 9135
9151 9136 if (job->job_result != FC_SUCCESS) {
9152 9137 fcio->fcio_errno = job->job_result;
9153 9138 rval = EIO;
9154 9139 if (fp_fcio_copyout(fcio, data, mode)) {
9155 9140 rval = EFAULT;
9156 9141 }
9157 9142 }
9158 9143 fctl_dealloc_job(job);
9159 9144 break;
9160 9145 }
9161 9146
9162 9147 case FCIO_RESET_HARD:
9163 9148 ret = port->fp_fca_tran->fca_reset(
9164 9149 port->fp_fca_handle, FC_FCA_RESET);
9165 9150 if (ret != FC_SUCCESS) {
9166 9151 fcio->fcio_errno = ret;
9167 9152 rval = EIO;
9168 9153 if (fp_fcio_copyout(fcio, data, mode)) {
9169 9154 rval = EFAULT;
9170 9155 }
9171 9156 }
9172 9157 break;
9173 9158
9174 9159 case FCIO_RESET_HARD_CORE:
9175 9160 ret = port->fp_fca_tran->fca_reset(
9176 9161 port->fp_fca_handle, FC_FCA_RESET_CORE);
9177 9162 if (ret != FC_SUCCESS) {
9178 9163 rval = EIO;
9179 9164 fcio->fcio_errno = ret;
9180 9165 if (fp_fcio_copyout(fcio, data, mode)) {
9181 9166 rval = EFAULT;
9182 9167 }
9183 9168 }
9184 9169 break;
9185 9170
9186 9171 case FCIO_DIAG: {
9187 9172 fc_fca_pm_t pm;
9188 9173
9189 9174 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9190 9175
9191 9176 /* Validate user buffer from ioctl call. */
9192 9177 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9193 9178 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9194 9179 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9195 9180 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9196 9181 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9197 9182 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9198 9183 rval = EFAULT;
9199 9184 break;
9200 9185 }
9201 9186
9202 9187 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9203 9188 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9204 9189 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9205 9190 fcio->fcio_ilen, mode)) {
9206 9191 rval = EFAULT;
9207 9192 goto fp_fcio_diag_cleanup;
9208 9193 }
9209 9194 }
9210 9195
9211 9196 if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9212 9197 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9213 9198 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9214 9199 fcio->fcio_alen, mode)) {
9215 9200 rval = EFAULT;
9216 9201 goto fp_fcio_diag_cleanup;
9217 9202 }
9218 9203 }
9219 9204
9220 9205 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9221 9206 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9222 9207 }
9223 9208
9224 9209 pm.pm_cmd_code = FC_PORT_DIAG;
9225 9210 pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9226 9211
9227 9212 ret = port->fp_fca_tran->fca_port_manage(
9228 9213 port->fp_fca_handle, &pm);
9229 9214
9230 9215 if (ret != FC_SUCCESS) {
9231 9216 if (ret == FC_INVALID_REQUEST) {
9232 9217 rval = ENOTTY;
9233 9218 } else {
9234 9219 rval = EIO;
9235 9220 }
9236 9221
9237 9222 fcio->fcio_errno = ret;
9238 9223 if (fp_fcio_copyout(fcio, data, mode)) {
9239 9224 rval = EFAULT;
9240 9225 }
9241 9226 goto fp_fcio_diag_cleanup;
9242 9227 }
9243 9228
9244 9229 /*
9245 9230 * pm_stat_len will contain the number of status bytes
9246 9231 * an FCA driver requires to return the complete status
9247 9232 * of the requested diag operation. If the user buffer
9248 9233 * is not large enough to hold the entire status, We
9249 9234 * copy only the portion of data the fits in the buffer and
9250 9235 * return a ENOMEM to the user application.
9251 9236 */
9252 9237 if (pm.pm_stat_len > fcio->fcio_olen) {
9253 9238 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9254 9239 "fp:FCIO_DIAG:status buffer too small\n");
9255 9240
9256 9241 rval = ENOMEM;
9257 9242 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9258 9243 fcio->fcio_olen, mode)) {
9259 9244 rval = EFAULT;
9260 9245 goto fp_fcio_diag_cleanup;
9261 9246 }
9262 9247 } else {
9263 9248 /*
9264 9249 * Copy only data pm_stat_len bytes of data
9265 9250 */
9266 9251 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9267 9252 pm.pm_stat_len, mode)) {
9268 9253 rval = EFAULT;
9269 9254 goto fp_fcio_diag_cleanup;
9270 9255 }
9271 9256 }
9272 9257
9273 9258 if (fp_fcio_copyout(fcio, data, mode)) {
9274 9259 rval = EFAULT;
9275 9260 }
9276 9261
9277 9262 fp_fcio_diag_cleanup:
9278 9263 if (pm.pm_cmd_buf != NULL) {
9279 9264 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9280 9265 }
9281 9266 if (pm.pm_data_buf != NULL) {
9282 9267 kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9283 9268 }
9284 9269 if (pm.pm_stat_buf != NULL) {
9285 9270 kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9286 9271 }
9287 9272
9288 9273 break;
9289 9274 }
9290 9275
9291 9276 case FCIO_GET_NODE_ID: {
9292 9277 /* validate parameters */
9293 9278 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9294 9279 fcio->fcio_olen < sizeof (fc_rnid_t)) {
9295 9280 rval = EINVAL;
9296 9281 break;
9297 9282 }
9298 9283
9299 9284 rval = fp_get_rnid(port, data, mode, fcio);
9300 9285
9301 9286 /* ioctl handling is over */
9302 9287 break;
9303 9288 }
9304 9289
9305 9290 case FCIO_SEND_NODE_ID: {
9306 9291 la_wwn_t pwwn;
9307 9292
9308 9293 /* validate parameters */
9309 9294 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9310 9295 fcio->fcio_xfer != FCIO_XFER_READ) {
9311 9296 rval = EINVAL;
9312 9297 break;
9313 9298 }
9314 9299
9315 9300 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9316 9301 sizeof (la_wwn_t), mode)) {
9317 9302 rval = EFAULT;
9318 9303 break;
9319 9304 }
9320 9305
9321 9306 rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9322 9307
9323 9308 /* ioctl handling is over */
9324 9309 break;
9325 9310 }
9326 9311
9327 9312 case FCIO_SET_NODE_ID: {
9328 9313 if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9329 9314 (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9330 9315 rval = EINVAL;
9331 9316 break;
9332 9317 }
9333 9318
9334 9319 rval = fp_set_rnid(port, data, mode, fcio);
9335 9320 break;
9336 9321 }
9337 9322
9338 9323 case FCIO_LINK_STATUS: {
9339 9324 fc_portid_t rls_req;
9340 9325 fc_rls_acc_t *rls_acc;
9341 9326 fc_fca_pm_t pm;
9342 9327 uint32_t dest, src_id;
9343 9328 fp_cmd_t *cmd;
9344 9329 fc_remote_port_t *pd;
9345 9330 uchar_t pd_flags;
9346 9331
9347 9332 /* validate parameters */
9348 9333 if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9349 9334 fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9350 9335 fcio->fcio_xfer != FCIO_XFER_RW) {
9351 9336 rval = EINVAL;
9352 9337 break;
9353 9338 }
9354 9339
9355 9340 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9356 9341 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9357 9342 rval = EINVAL;
9358 9343 break;
9359 9344 }
9360 9345
9361 9346 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9362 9347 sizeof (fc_portid_t), mode)) {
9363 9348 rval = EFAULT;
9364 9349 break;
9365 9350 }
9366 9351
9367 9352
9368 9353 /* Determine the destination of the RLS frame */
9369 9354 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9370 9355 dest = FS_FABRIC_F_PORT;
9371 9356 } else {
9372 9357 dest = rls_req.port_id;
9373 9358 }
9374 9359
9375 9360 mutex_enter(&port->fp_mutex);
9376 9361 src_id = port->fp_port_id.port_id;
9377 9362 mutex_exit(&port->fp_mutex);
9378 9363
9379 9364 /* If dest is zero OR same as FCA ID, then use port_manage() */
9380 9365 if (dest == 0 || dest == src_id) {
9381 9366
9382 9367 /* Allocate memory for link error status block */
9383 9368 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9384 9369 ASSERT(rls_acc != NULL);
9385 9370
9386 9371 /* Prepare the port management structure */
9387 9372 bzero((caddr_t)&pm, sizeof (pm));
9388 9373
9389 9374 pm.pm_cmd_flags = FC_FCA_PM_READ;
9390 9375 pm.pm_cmd_code = FC_PORT_RLS;
9391 9376 pm.pm_data_len = sizeof (*rls_acc);
9392 9377 pm.pm_data_buf = (caddr_t)rls_acc;
9393 9378
9394 9379 /* Get the adapter's link error status block */
9395 9380 ret = port->fp_fca_tran->fca_port_manage(
9396 9381 port->fp_fca_handle, &pm);
9397 9382
9398 9383 if (ret == FC_SUCCESS) {
9399 9384 /* xfer link status block to userland */
9400 9385 if (ddi_copyout((void *)rls_acc,
9401 9386 (void *)fcio->fcio_obuf,
9402 9387 sizeof (*rls_acc), mode) == 0) {
9403 9388 if (fp_fcio_copyout(fcio, data,
9404 9389 mode)) {
9405 9390 rval = EFAULT;
9406 9391 }
9407 9392 } else {
9408 9393 rval = EFAULT;
9409 9394 }
9410 9395 } else {
9411 9396 rval = EIO;
9412 9397 fcio->fcio_errno = ret;
9413 9398 if (fp_fcio_copyout(fcio, data, mode)) {
9414 9399 rval = EFAULT;
9415 9400 }
9416 9401 }
9417 9402
9418 9403 kmem_free(rls_acc, sizeof (*rls_acc));
9419 9404
9420 9405 /* ioctl handling is over */
9421 9406 break;
9422 9407 }
9423 9408
9424 9409 /*
9425 9410 * Send RLS to the destination port.
9426 9411 * Having RLS frame destination is as FPORT is not yet
9427 9412 * supported and will be implemented in future, if needed.
9428 9413 * Following call to get "pd" will fail if dest is FPORT
9429 9414 */
9430 9415 pd = fctl_hold_remote_port_by_did(port, dest);
9431 9416 if (pd == NULL) {
9432 9417 fcio->fcio_errno = FC_BADOBJECT;
9433 9418 rval = ENXIO;
9434 9419 if (fp_fcio_copyout(fcio, data, mode)) {
9435 9420 rval = EFAULT;
9436 9421 }
9437 9422 break;
9438 9423 }
9439 9424
9440 9425 mutex_enter(&pd->pd_mutex);
9441 9426 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9442 9427 mutex_exit(&pd->pd_mutex);
9443 9428 fctl_release_remote_port(pd);
9444 9429
9445 9430 fcio->fcio_errno = FC_LOGINREQ;
9446 9431 rval = EINVAL;
9447 9432 if (fp_fcio_copyout(fcio, data, mode)) {
9448 9433 rval = EFAULT;
9449 9434 }
9450 9435 break;
9451 9436 }
9452 9437 ASSERT(pd->pd_login_count >= 1);
9453 9438 mutex_exit(&pd->pd_mutex);
9454 9439
9455 9440 /*
9456 9441 * Allocate job structure and set job_code as DUMMY,
9457 9442 * because we will not go through the job thread.
9458 9443 * Instead fp_sendcmd() is called directly here.
9459 9444 */
9460 9445 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9461 9446 NULL, NULL, KM_SLEEP);
9462 9447 ASSERT(job != NULL);
9463 9448
9464 9449 job->job_counter = 1;
9465 9450
9466 9451 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9467 9452 sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9468 9453 if (cmd == NULL) {
9469 9454 fcio->fcio_errno = FC_NOMEM;
9470 9455 rval = ENOMEM;
9471 9456
9472 9457 fctl_release_remote_port(pd);
9473 9458
9474 9459 fctl_dealloc_job(job);
9475 9460 if (fp_fcio_copyout(fcio, data, mode)) {
9476 9461 rval = EFAULT;
9477 9462 }
9478 9463 break;
9479 9464 }
9480 9465
9481 9466 /* Allocate memory for link error status block */
9482 9467 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9483 9468
9484 9469 mutex_enter(&port->fp_mutex);
9485 9470 mutex_enter(&pd->pd_mutex);
9486 9471
9487 9472 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9488 9473 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9489 9474 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9490 9475 cmd->cmd_retry_count = 1;
9491 9476 cmd->cmd_ulp_pkt = NULL;
9492 9477
9493 9478 fp_rls_init(cmd, job);
9494 9479
9495 9480 job->job_private = (void *)rls_acc;
9496 9481
9497 9482 pd_flags = pd->pd_flags;
9498 9483 pd->pd_flags = PD_ELS_IN_PROGRESS;
9499 9484
9500 9485 mutex_exit(&pd->pd_mutex);
9501 9486 mutex_exit(&port->fp_mutex);
9502 9487
9503 9488 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9504 9489 fctl_jobwait(job);
9505 9490
9506 9491 fcio->fcio_errno = job->job_result;
9507 9492 if (job->job_result == FC_SUCCESS) {
9508 9493 ASSERT(pd != NULL);
9509 9494 /*
9510 9495 * link error status block is now available.
9511 9496 * Copy it to userland
9512 9497 */
9513 9498 ASSERT(job->job_private == (void *)rls_acc);
9514 9499 if (ddi_copyout((void *)rls_acc,
9515 9500 (void *)fcio->fcio_obuf,
9516 9501 sizeof (*rls_acc), mode) == 0) {
9517 9502 if (fp_fcio_copyout(fcio, data,
9518 9503 mode)) {
9519 9504 rval = EFAULT;
9520 9505 }
9521 9506 } else {
9522 9507 rval = EFAULT;
9523 9508 }
9524 9509 } else {
9525 9510 rval = EIO;
9526 9511 }
9527 9512 } else {
9528 9513 rval = EIO;
9529 9514 fp_free_pkt(cmd);
9530 9515 }
9531 9516
9532 9517 if (rval) {
9533 9518 mutex_enter(&port->fp_mutex);
9534 9519 mutex_enter(&pd->pd_mutex);
9535 9520 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9536 9521 pd->pd_flags = pd_flags;
9537 9522 }
9538 9523 mutex_exit(&pd->pd_mutex);
9539 9524 mutex_exit(&port->fp_mutex);
9540 9525 }
9541 9526
9542 9527 fctl_release_remote_port(pd);
9543 9528 fctl_dealloc_job(job);
9544 9529 kmem_free(rls_acc, sizeof (*rls_acc));
9545 9530
9546 9531 if (fp_fcio_copyout(fcio, data, mode)) {
9547 9532 rval = EFAULT;
9548 9533 }
9549 9534 break;
9550 9535 }
9551 9536
9552 9537 case FCIO_NS: {
9553 9538 fc_ns_cmd_t *ns_req;
9554 9539 fc_ns_cmd32_t *ns_req32;
9555 9540 fctl_ns_req_t *ns_cmd;
9556 9541
9557 9542 if (use32 == B_TRUE) {
9558 9543 if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9559 9544 rval = EINVAL;
9560 9545 break;
9561 9546 }
9562 9547
9563 9548 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9564 9549 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9565 9550
9566 9551 if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9567 9552 sizeof (*ns_req32), mode)) {
9568 9553 rval = EFAULT;
9569 9554 kmem_free(ns_req, sizeof (*ns_req));
9570 9555 kmem_free(ns_req32, sizeof (*ns_req32));
9571 9556 break;
9572 9557 }
9573 9558
9574 9559 ns_req->ns_flags = ns_req32->ns_flags;
9575 9560 ns_req->ns_cmd = ns_req32->ns_cmd;
9576 9561 ns_req->ns_req_len = ns_req32->ns_req_len;
9577 9562 ns_req->ns_req_payload = ns_req32->ns_req_payload;
9578 9563 ns_req->ns_resp_len = ns_req32->ns_resp_len;
9579 9564 ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9580 9565 ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9581 9566 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9582 9567
9583 9568 kmem_free(ns_req32, sizeof (*ns_req32));
9584 9569 } else {
9585 9570 if (fcio->fcio_ilen != sizeof (*ns_req)) {
9586 9571 rval = EINVAL;
9587 9572 break;
9588 9573 }
9589 9574
9590 9575 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9591 9576
9592 9577 if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9593 9578 sizeof (fc_ns_cmd_t), mode)) {
9594 9579 rval = EFAULT;
9595 9580 kmem_free(ns_req, sizeof (*ns_req));
9596 9581 break;
9597 9582 }
9598 9583 }
9599 9584
9600 9585 if (ns_req->ns_req_len <= 0) {
9601 9586 rval = EINVAL;
9602 9587 kmem_free(ns_req, sizeof (*ns_req));
9603 9588 break;
9604 9589 }
9605 9590
9606 9591 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9607 9592 ASSERT(job != NULL);
9608 9593
9609 9594 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9610 9595 ns_req->ns_resp_len, ns_req->ns_resp_len,
9611 9596 FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9612 9597 ASSERT(ns_cmd != NULL);
9613 9598 ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9614 9599
9615 9600 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9616 9601 ns_cmd->ns_gan_max = 1;
9617 9602 ns_cmd->ns_gan_index = 0;
9618 9603 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9619 9604 }
9620 9605
9621 9606 if (ddi_copyin(ns_req->ns_req_payload,
9622 9607 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9623 9608 rval = EFAULT;
9624 9609 fctl_free_ns_cmd(ns_cmd);
9625 9610 fctl_dealloc_job(job);
9626 9611 kmem_free(ns_req, sizeof (*ns_req));
9627 9612 break;
9628 9613 }
9629 9614
9630 9615 job->job_private = (void *)ns_cmd;
9631 9616 fctl_enque_job(port, job);
9632 9617 fctl_jobwait(job);
9633 9618 rval = job->job_result;
9634 9619
9635 9620 if (rval == FC_SUCCESS) {
9636 9621 if (ns_req->ns_resp_len) {
9637 9622 if (ddi_copyout(ns_cmd->ns_data_buf,
9638 9623 ns_req->ns_resp_payload,
9639 9624 ns_cmd->ns_data_len, mode)) {
9640 9625 rval = EFAULT;
9641 9626 fctl_free_ns_cmd(ns_cmd);
9642 9627 fctl_dealloc_job(job);
9643 9628 kmem_free(ns_req, sizeof (*ns_req));
9644 9629 break;
9645 9630 }
9646 9631 }
9647 9632 } else {
9648 9633 rval = EIO;
9649 9634 }
9650 9635 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9651 9636 fctl_free_ns_cmd(ns_cmd);
9652 9637 fctl_dealloc_job(job);
9653 9638 kmem_free(ns_req, sizeof (*ns_req));
9654 9639
9655 9640 if (fp_fcio_copyout(fcio, data, mode)) {
9656 9641 rval = EFAULT;
9657 9642 }
9658 9643 break;
9659 9644 }
9660 9645
9661 9646 default:
9662 9647 rval = ENOTTY;
9663 9648 break;
9664 9649 }
9665 9650
9666 9651 /*
9667 9652 * If set, reset the EXCL busy bit to
9668 9653 * receive other exclusive access commands
9669 9654 */
9670 9655 mutex_enter(&port->fp_mutex);
9671 9656 if (port->fp_flag & FP_EXCL_BUSY) {
9672 9657 port->fp_flag &= ~FP_EXCL_BUSY;
9673 9658 }
9674 9659 mutex_exit(&port->fp_mutex);
9675 9660
9676 9661 return (rval);
9677 9662 }
9678 9663
9679 9664
9680 9665 /*
9681 9666 * This function assumes that the response length
9682 9667 * is same regardless of data model (LP32 or LP64)
9683 9668 * which is true for all the ioctls currently
9684 9669 * supported.
9685 9670 */
9686 9671 static int
9687 9672 fp_copyout(void *from, void *to, size_t len, int mode)
9688 9673 {
9689 9674 return (ddi_copyout(from, to, len, mode));
9690 9675 }
9691 9676
9692 9677 /*
9693 9678 * This function does the set rnid
9694 9679 */
9695 9680 static int
9696 9681 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9697 9682 {
9698 9683 int rval = 0;
9699 9684 fc_rnid_t *rnid;
9700 9685 fc_fca_pm_t pm;
9701 9686
9702 9687 /* Allocate memory for node id block */
9703 9688 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9704 9689
9705 9690 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9706 9691 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9707 9692 kmem_free(rnid, sizeof (fc_rnid_t));
9708 9693 return (EFAULT);
9709 9694 }
9710 9695
9711 9696 /* Prepare the port management structure */
9712 9697 bzero((caddr_t)&pm, sizeof (pm));
9713 9698
9714 9699 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9715 9700 pm.pm_cmd_code = FC_PORT_SET_NODE_ID;
9716 9701 pm.pm_data_len = sizeof (*rnid);
9717 9702 pm.pm_data_buf = (caddr_t)rnid;
9718 9703
9719 9704 /* Get the adapter's node data */
9720 9705 rval = port->fp_fca_tran->fca_port_manage(
9721 9706 port->fp_fca_handle, &pm);
9722 9707
9723 9708 if (rval != FC_SUCCESS) {
9724 9709 fcio->fcio_errno = rval;
9725 9710 rval = EIO;
9726 9711 if (fp_fcio_copyout(fcio, data, mode)) {
9727 9712 rval = EFAULT;
9728 9713 }
9729 9714 } else {
9730 9715 mutex_enter(&port->fp_mutex);
9731 9716 /* copy to the port structure */
9732 9717 bcopy(rnid, &port->fp_rnid_params,
9733 9718 sizeof (port->fp_rnid_params));
9734 9719 mutex_exit(&port->fp_mutex);
9735 9720 }
9736 9721
9737 9722 kmem_free(rnid, sizeof (fc_rnid_t));
9738 9723
9739 9724 if (rval != FC_SUCCESS) {
9740 9725 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9741 9726 }
9742 9727
9743 9728 return (rval);
9744 9729 }
9745 9730
9746 9731 /*
9747 9732 * This function does the local pwwn get rnid
9748 9733 */
9749 9734 static int
9750 9735 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9751 9736 {
9752 9737 fc_rnid_t *rnid;
9753 9738 fc_fca_pm_t pm;
9754 9739 int rval = 0;
9755 9740 uint32_t ret;
9756 9741
9757 9742 /* Allocate memory for rnid data block */
9758 9743 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9759 9744
9760 9745 mutex_enter(&port->fp_mutex);
9761 9746 if (port->fp_rnid_init == 1) {
9762 9747 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9763 9748 mutex_exit(&port->fp_mutex);
9764 9749 /* xfer node info to userland */
9765 9750 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9766 9751 sizeof (*rnid), mode) == 0) {
9767 9752 if (fp_fcio_copyout(fcio, data, mode)) {
9768 9753 rval = EFAULT;
9769 9754 }
9770 9755 } else {
9771 9756 rval = EFAULT;
9772 9757 }
9773 9758
9774 9759 kmem_free(rnid, sizeof (fc_rnid_t));
9775 9760
9776 9761 if (rval != FC_SUCCESS) {
9777 9762 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9778 9763 rval);
9779 9764 }
9780 9765
9781 9766 return (rval);
9782 9767 }
9783 9768 mutex_exit(&port->fp_mutex);
9784 9769
9785 9770 /* Prepare the port management structure */
9786 9771 bzero((caddr_t)&pm, sizeof (pm));
9787 9772
9788 9773 pm.pm_cmd_flags = FC_FCA_PM_READ;
9789 9774 pm.pm_cmd_code = FC_PORT_GET_NODE_ID;
9790 9775 pm.pm_data_len = sizeof (fc_rnid_t);
9791 9776 pm.pm_data_buf = (caddr_t)rnid;
9792 9777
9793 9778 /* Get the adapter's node data */
9794 9779 ret = port->fp_fca_tran->fca_port_manage(
9795 9780 port->fp_fca_handle,
9796 9781 &pm);
9797 9782
9798 9783 if (ret == FC_SUCCESS) {
9799 9784 /* initialize in the port_info */
9800 9785 mutex_enter(&port->fp_mutex);
9801 9786 port->fp_rnid_init = 1;
9802 9787 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9803 9788 mutex_exit(&port->fp_mutex);
9804 9789
9805 9790 /* xfer node info to userland */
9806 9791 if (ddi_copyout((void *)rnid,
9807 9792 (void *)fcio->fcio_obuf,
9808 9793 sizeof (*rnid), mode) == 0) {
9809 9794 if (fp_fcio_copyout(fcio, data,
9810 9795 mode)) {
9811 9796 rval = EFAULT;
9812 9797 }
9813 9798 } else {
9814 9799 rval = EFAULT;
9815 9800 }
9816 9801 } else {
9817 9802 rval = EIO;
9818 9803 fcio->fcio_errno = ret;
9819 9804 if (fp_fcio_copyout(fcio, data, mode)) {
9820 9805 rval = EFAULT;
9821 9806 }
9822 9807 }
9823 9808
9824 9809 kmem_free(rnid, sizeof (fc_rnid_t));
9825 9810
9826 9811 if (rval != FC_SUCCESS) {
9827 9812 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9828 9813 }
9829 9814
9830 9815 return (rval);
9831 9816 }
9832 9817
9833 9818 static int
9834 9819 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9835 9820 la_wwn_t *pwwn)
9836 9821 {
9837 9822 int rval = 0;
9838 9823 fc_remote_port_t *pd;
9839 9824 fp_cmd_t *cmd;
9840 9825 job_request_t *job;
9841 9826 la_els_rnid_acc_t *rnid_acc;
9842 9827
9843 9828 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9844 9829 if (pd == NULL) {
9845 9830 /*
9846 9831 * We can safely assume that the destination port
9847 9832 * is logged in. Either the user land will explicitly
9848 9833 * login before issuing RNID ioctl or the device would
9849 9834 * have been configured, meaning already logged in.
9850 9835 */
9851 9836
9852 9837 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9853 9838
9854 9839 return (ENXIO);
9855 9840 }
9856 9841 /*
9857 9842 * Allocate job structure and set job_code as DUMMY,
9858 9843 * because we will not go thorugh the job thread.
9859 9844 * Instead fp_sendcmd() is called directly here.
9860 9845 */
9861 9846 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9862 9847 NULL, NULL, KM_SLEEP);
9863 9848
9864 9849 ASSERT(job != NULL);
9865 9850
9866 9851 job->job_counter = 1;
9867 9852
9868 9853 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9869 9854 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9870 9855 if (cmd == NULL) {
9871 9856 fcio->fcio_errno = FC_NOMEM;
9872 9857 rval = ENOMEM;
9873 9858
9874 9859 fctl_dealloc_job(job);
9875 9860 if (fp_fcio_copyout(fcio, data, mode)) {
9876 9861 rval = EFAULT;
9877 9862 }
9878 9863
9879 9864 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9880 9865
9881 9866 return (rval);
9882 9867 }
9883 9868
9884 9869 /* Allocate memory for node id accept block */
9885 9870 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9886 9871
9887 9872 mutex_enter(&port->fp_mutex);
9888 9873 mutex_enter(&pd->pd_mutex);
9889 9874
9890 9875 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9891 9876 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9892 9877 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9893 9878 cmd->cmd_retry_count = 1;
9894 9879 cmd->cmd_ulp_pkt = NULL;
9895 9880
9896 9881 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9897 9882
9898 9883 job->job_private = (void *)rnid_acc;
9899 9884
9900 9885 pd->pd_flags = PD_ELS_IN_PROGRESS;
9901 9886
9902 9887 mutex_exit(&pd->pd_mutex);
9903 9888 mutex_exit(&port->fp_mutex);
9904 9889
9905 9890 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9906 9891 fctl_jobwait(job);
9907 9892 fcio->fcio_errno = job->job_result;
9908 9893 if (job->job_result == FC_SUCCESS) {
9909 9894 int rnid_cnt;
9910 9895 ASSERT(pd != NULL);
9911 9896 /*
9912 9897 * node id block is now available.
9913 9898 * Copy it to userland
9914 9899 */
9915 9900 ASSERT(job->job_private == (void *)rnid_acc);
9916 9901
9917 9902 /* get the response length */
9918 9903 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9919 9904 rnid_acc->hdr.cmn_len +
9920 9905 rnid_acc->hdr.specific_len;
9921 9906
9922 9907 if (fcio->fcio_olen < rnid_cnt) {
9923 9908 rval = EINVAL;
9924 9909 } else if (ddi_copyout((void *)rnid_acc,
9925 9910 (void *)fcio->fcio_obuf,
9926 9911 rnid_cnt, mode) == 0) {
9927 9912 if (fp_fcio_copyout(fcio, data,
9928 9913 mode)) {
9929 9914 rval = EFAULT;
9930 9915 }
9931 9916 } else {
9932 9917 rval = EFAULT;
9933 9918 }
9934 9919 } else {
9935 9920 rval = EIO;
9936 9921 }
9937 9922 } else {
9938 9923 rval = EIO;
9939 9924 if (pd) {
9940 9925 mutex_enter(&pd->pd_mutex);
9941 9926 pd->pd_flags = PD_IDLE;
9942 9927 mutex_exit(&pd->pd_mutex);
9943 9928 }
9944 9929 fp_free_pkt(cmd);
9945 9930 }
9946 9931
9947 9932 fctl_dealloc_job(job);
9948 9933 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9949 9934
9950 9935 if (fp_fcio_copyout(fcio, data, mode)) {
9951 9936 rval = EFAULT;
9952 9937 }
9953 9938
9954 9939 if (rval != FC_SUCCESS) {
9955 9940 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9956 9941 }
9957 9942
9958 9943 return (rval);
9959 9944 }
9960 9945
9961 9946 /*
9962 9947 * Copy out to userland
9963 9948 */
9964 9949 static int
9965 9950 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9966 9951 {
9967 9952 int rval;
9968 9953
9969 9954 #ifdef _MULTI_DATAMODEL
9970 9955 switch (ddi_model_convert_from(mode & FMODELS)) {
9971 9956 case DDI_MODEL_ILP32: {
9972 9957 struct fcio32 fcio32;
9973 9958
9974 9959 fcio32.fcio_xfer = fcio->fcio_xfer;
9975 9960 fcio32.fcio_cmd = fcio->fcio_cmd;
9976 9961 fcio32.fcio_flags = fcio->fcio_flags;
9977 9962 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9978 9963 fcio32.fcio_ilen = fcio->fcio_ilen;
9979 9964 fcio32.fcio_ibuf =
9980 9965 (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9981 9966 fcio32.fcio_olen = fcio->fcio_olen;
9982 9967 fcio32.fcio_obuf =
9983 9968 (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9984 9969 fcio32.fcio_alen = fcio->fcio_alen;
9985 9970 fcio32.fcio_abuf =
9986 9971 (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9987 9972 fcio32.fcio_errno = fcio->fcio_errno;
9988 9973
9989 9974 rval = ddi_copyout((void *)&fcio32, (void *)data,
9990 9975 sizeof (struct fcio32), mode);
9991 9976 break;
9992 9977 }
9993 9978 case DDI_MODEL_NONE:
9994 9979 rval = ddi_copyout((void *)fcio, (void *)data,
9995 9980 sizeof (fcio_t), mode);
9996 9981 break;
9997 9982 }
9998 9983 #else
9999 9984 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
10000 9985 #endif
10001 9986
10002 9987 return (rval);
10003 9988 }
10004 9989
10005 9990
10006 9991 static void
10007 9992 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
10008 9993 {
10009 9994 uint32_t listlen;
10010 9995 fc_portmap_t *changelist;
10011 9996
10012 9997 ASSERT(MUTEX_HELD(&port->fp_mutex));
10013 9998 ASSERT(port->fp_topology == FC_TOP_PT_PT);
10014 9999 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10015 10000
10016 10001 listlen = 0;
10017 10002 changelist = NULL;
10018 10003
10019 10004 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10020 10005 if (port->fp_statec_busy > 1) {
10021 10006 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10022 10007 }
10023 10008 }
10024 10009 mutex_exit(&port->fp_mutex);
10025 10010
10026 10011 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10027 10012 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10028 10013 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10029 10014 listlen, listlen, KM_SLEEP);
10030 10015
10031 10016 mutex_enter(&port->fp_mutex);
10032 10017 } else {
10033 10018 ASSERT(changelist == NULL && listlen == 0);
10034 10019 mutex_enter(&port->fp_mutex);
10035 10020 if (--port->fp_statec_busy == 0) {
10036 10021 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10037 10022 }
10038 10023 }
10039 10024 }
10040 10025
10041 10026 static int
10042 10027 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10043 10028 {
10044 10029 int rval;
10045 10030 int count;
10046 10031 int index;
10047 10032 int num_devices;
10048 10033 fc_remote_node_t *node;
10049 10034 fc_port_dev_t *devlist;
10050 10035 struct pwwn_hash *head;
10051 10036 fc_remote_port_t *pd;
10052 10037
10053 10038 ASSERT(MUTEX_HELD(&port->fp_mutex));
10054 10039
10055 10040 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10056 10041
10057 10042 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
10058 10043
10059 10044 for (count = index = 0; index < pwwn_table_size; index++) {
10060 10045 head = &port->fp_pwwn_table[index];
10061 10046 pd = head->pwwn_head;
10062 10047 while (pd != NULL) {
10063 10048 mutex_enter(&pd->pd_mutex);
10064 10049 if (pd->pd_state == PORT_DEVICE_INVALID) {
10065 10050 mutex_exit(&pd->pd_mutex);
10066 10051 pd = pd->pd_wwn_hnext;
10067 10052 continue;
10068 10053 }
10069 10054
10070 10055 devlist[count].dev_state = pd->pd_state;
10071 10056 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10072 10057 devlist[count].dev_did = pd->pd_port_id;
10073 10058 devlist[count].dev_did.priv_lilp_posit =
10074 10059 (uint8_t)(index & 0xff);
10075 10060 bcopy((caddr_t)pd->pd_fc4types,
10076 10061 (caddr_t)devlist[count].dev_type,
10077 10062 sizeof (pd->pd_fc4types));
10078 10063
10079 10064 bcopy((caddr_t)&pd->pd_port_name,
10080 10065 (caddr_t)&devlist[count].dev_pwwn,
10081 10066 sizeof (la_wwn_t));
10082 10067
10083 10068 node = pd->pd_remote_nodep;
10084 10069 mutex_exit(&pd->pd_mutex);
10085 10070
10086 10071 if (node) {
10087 10072 mutex_enter(&node->fd_mutex);
10088 10073 bcopy((caddr_t)&node->fd_node_name,
10089 10074 (caddr_t)&devlist[count].dev_nwwn,
10090 10075 sizeof (la_wwn_t));
10091 10076 mutex_exit(&node->fd_mutex);
10092 10077 }
10093 10078 count++;
10094 10079 if (count >= num_devices) {
10095 10080 goto found;
10096 10081 }
10097 10082 }
10098 10083 }
10099 10084 found:
10100 10085 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10101 10086 sizeof (count), mode)) {
10102 10087 rval = FC_FAILURE;
10103 10088 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10104 10089 sizeof (fc_port_dev_t) * num_devices, mode)) {
10105 10090 rval = FC_FAILURE;
10106 10091 } else {
10107 10092 rval = FC_SUCCESS;
10108 10093 }
10109 10094
10110 10095 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10111 10096
10112 10097 return (rval);
10113 10098 }
10114 10099
10115 10100
10116 10101 /*
10117 10102 * Handle Fabric ONLINE
10118 10103 */
10119 10104 static void
10120 10105 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10121 10106 {
10122 10107 int index;
10123 10108 int rval;
10124 10109 int dbg_count;
10125 10110 int count = 0;
10126 10111 char ww_name[17];
10127 10112 uint32_t d_id;
10128 10113 uint32_t listlen;
10129 10114 fctl_ns_req_t *ns_cmd;
10130 10115 struct pwwn_hash *head;
10131 10116 fc_remote_port_t *pd;
10132 10117 fc_remote_port_t *npd;
10133 10118 fc_portmap_t *changelist;
10134 10119
10135 10120 ASSERT(MUTEX_HELD(&port->fp_mutex));
10136 10121 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10137 10122 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10138 10123
10139 10124 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10140 10125 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10141 10126 0, KM_SLEEP);
10142 10127
10143 10128 ASSERT(ns_cmd != NULL);
10144 10129
10145 10130 ns_cmd->ns_cmd_code = NS_GID_PN;
10146 10131
10147 10132 /*
10148 10133 * Check if orphans are showing up now
10149 10134 */
10150 10135 if (port->fp_orphan_count) {
10151 10136 fc_orphan_t *orp;
10152 10137 fc_orphan_t *norp = NULL;
10153 10138 fc_orphan_t *prev = NULL;
10154 10139
10155 10140 for (orp = port->fp_orphan_list; orp; orp = norp) {
10156 10141 norp = orp->orp_next;
10157 10142 mutex_exit(&port->fp_mutex);
10158 10143 orp->orp_nscan++;
10159 10144
10160 10145 job->job_counter = 1;
10161 10146 job->job_result = FC_SUCCESS;
10162 10147
10163 10148 ((ns_req_gid_pn_t *)
10164 10149 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10165 10150 ((ns_resp_gid_pn_t *)
10166 10151 ns_cmd->ns_data_buf)->pid.port_id = 0;
10167 10152 ((ns_resp_gid_pn_t *)
10168 10153 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10169 10154
10170 10155 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10171 10156 if (rval == FC_SUCCESS) {
10172 10157 d_id =
10173 10158 BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10174 10159 pd = fp_create_remote_port_by_ns(port,
10175 10160 d_id, KM_SLEEP);
10176 10161
10177 10162 if (pd != NULL) {
10178 10163 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10179 10164
10180 10165 fp_printf(port, CE_WARN, FP_LOG_ONLY,
10181 10166 0, NULL, "N_x Port with D_ID=%x,"
10182 10167 " PWWN=%s reappeared in fabric",
10183 10168 d_id, ww_name);
10184 10169
10185 10170 mutex_enter(&port->fp_mutex);
10186 10171 if (prev) {
10187 10172 prev->orp_next = orp->orp_next;
10188 10173 } else {
10189 10174 ASSERT(orp ==
10190 10175 port->fp_orphan_list);
10191 10176 port->fp_orphan_list =
10192 10177 orp->orp_next;
10193 10178 }
10194 10179 port->fp_orphan_count--;
10195 10180 mutex_exit(&port->fp_mutex);
10196 10181 kmem_free(orp, sizeof (*orp));
10197 10182 count++;
10198 10183
10199 10184 mutex_enter(&pd->pd_mutex);
10200 10185 pd->pd_flags = PD_ELS_MARK;
10201 10186
10202 10187 mutex_exit(&pd->pd_mutex);
10203 10188 } else {
10204 10189 prev = orp;
10205 10190 }
10206 10191 } else {
10207 10192 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10208 10193 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10209 10194
10210 10195 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10211 10196 NULL,
10212 10197 " Port WWN %s removed from orphan"
10213 10198 " list after %d scans", ww_name,
10214 10199 orp->orp_nscan);
10215 10200
10216 10201 mutex_enter(&port->fp_mutex);
10217 10202 if (prev) {
10218 10203 prev->orp_next = orp->orp_next;
10219 10204 } else {
10220 10205 ASSERT(orp ==
10221 10206 port->fp_orphan_list);
10222 10207 port->fp_orphan_list =
10223 10208 orp->orp_next;
10224 10209 }
10225 10210 port->fp_orphan_count--;
10226 10211 mutex_exit(&port->fp_mutex);
10227 10212
10228 10213 kmem_free(orp, sizeof (*orp));
10229 10214 } else {
10230 10215 prev = orp;
10231 10216 }
10232 10217 }
10233 10218 mutex_enter(&port->fp_mutex);
10234 10219 }
10235 10220 }
10236 10221
10237 10222 /*
10238 10223 * Walk the Port WWN hash table, reestablish LOGIN
10239 10224 * if a LOGIN is already performed on a particular
10240 10225 * device; Any failure to LOGIN should mark the
10241 10226 * port device OLD.
10242 10227 */
10243 10228 for (index = 0; index < pwwn_table_size; index++) {
10244 10229 head = &port->fp_pwwn_table[index];
10245 10230 npd = head->pwwn_head;
10246 10231
10247 10232 while ((pd = npd) != NULL) {
10248 10233 la_wwn_t *pwwn;
10249 10234
10250 10235 npd = pd->pd_wwn_hnext;
10251 10236
10252 10237 /*
10253 10238 * Don't count in the port devices that are new
10254 10239 * unless the total number of devices visible
10255 10240 * through this port is less than FP_MAX_DEVICES
10256 10241 */
10257 10242 mutex_enter(&pd->pd_mutex);
10258 10243 if (port->fp_dev_count >= FP_MAX_DEVICES ||
10259 10244 (port->fp_options & FP_TARGET_MODE)) {
10260 10245 if (pd->pd_type == PORT_DEVICE_NEW ||
10261 10246 pd->pd_flags == PD_ELS_MARK ||
10262 10247 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10263 10248 mutex_exit(&pd->pd_mutex);
10264 10249 continue;
10265 10250 }
10266 10251 } else {
10267 10252 if (pd->pd_flags == PD_ELS_MARK ||
10268 10253 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10269 10254 mutex_exit(&pd->pd_mutex);
10270 10255 continue;
10271 10256 }
10272 10257 pd->pd_type = PORT_DEVICE_OLD;
10273 10258 }
10274 10259 count++;
10275 10260
10276 10261 /*
10277 10262 * Consult with the name server about D_ID changes
10278 10263 */
10279 10264 job->job_counter = 1;
10280 10265 job->job_result = FC_SUCCESS;
10281 10266
10282 10267 ((ns_req_gid_pn_t *)
10283 10268 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10284 10269 ((ns_resp_gid_pn_t *)
10285 10270 ns_cmd->ns_data_buf)->pid.port_id = 0;
10286 10271
10287 10272 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10288 10273 pid.priv_lilp_posit = 0;
10289 10274
10290 10275 pwwn = &pd->pd_port_name;
10291 10276 pd->pd_flags = PD_ELS_MARK;
10292 10277
10293 10278 mutex_exit(&pd->pd_mutex);
10294 10279 mutex_exit(&port->fp_mutex);
10295 10280
10296 10281 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10297 10282 if (rval != FC_SUCCESS) {
10298 10283 fc_wwn_to_str(pwwn, ww_name);
10299 10284
10300 10285 mutex_enter(&pd->pd_mutex);
10301 10286 d_id = pd->pd_port_id.port_id;
10302 10287 pd->pd_type = PORT_DEVICE_DELETE;
10303 10288 mutex_exit(&pd->pd_mutex);
10304 10289
10305 10290 FP_TRACE(FP_NHEAD1(3, 0),
10306 10291 "fp_fabric_online: PD "
10307 10292 "disappeared; d_id=%x, PWWN=%s",
10308 10293 d_id, ww_name);
10309 10294
10310 10295 FP_TRACE(FP_NHEAD2(9, 0),
10311 10296 "N_x Port with D_ID=%x, PWWN=%s"
10312 10297 " disappeared from fabric", d_id,
10313 10298 ww_name);
10314 10299
10315 10300 mutex_enter(&port->fp_mutex);
10316 10301 continue;
10317 10302 }
10318 10303
10319 10304 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10320 10305
10321 10306 mutex_enter(&port->fp_mutex);
10322 10307 mutex_enter(&pd->pd_mutex);
10323 10308 if (d_id != pd->pd_port_id.port_id) {
10324 10309 fctl_delist_did_table(port, pd);
10325 10310 fc_wwn_to_str(pwwn, ww_name);
10326 10311
10327 10312 FP_TRACE(FP_NHEAD2(9, 0),
10328 10313 "D_ID of a device with PWWN %s changed."
10329 10314 " New D_ID = %x, OLD D_ID = %x", ww_name,
10330 10315 d_id, pd->pd_port_id.port_id);
10331 10316
10332 10317 pd->pd_port_id.port_id = BE_32(d_id);
10333 10318 pd->pd_type = PORT_DEVICE_CHANGED;
10334 10319 fctl_enlist_did_table(port, pd);
10335 10320 }
10336 10321 mutex_exit(&pd->pd_mutex);
10337 10322
10338 10323 }
10339 10324 }
10340 10325
10341 10326 if (ns_cmd) {
10342 10327 fctl_free_ns_cmd(ns_cmd);
10343 10328 }
10344 10329
10345 10330 listlen = 0;
10346 10331 changelist = NULL;
10347 10332 if (count) {
10348 10333 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10349 10334 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10350 10335 mutex_exit(&port->fp_mutex);
10351 10336 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10352 10337 mutex_enter(&port->fp_mutex);
10353 10338 }
10354 10339
10355 10340 dbg_count = 0;
10356 10341
10357 10342 job->job_counter = count;
10358 10343
10359 10344 for (index = 0; index < pwwn_table_size; index++) {
10360 10345 head = &port->fp_pwwn_table[index];
10361 10346 npd = head->pwwn_head;
10362 10347
10363 10348 while ((pd = npd) != NULL) {
10364 10349 npd = pd->pd_wwn_hnext;
10365 10350
10366 10351 mutex_enter(&pd->pd_mutex);
10367 10352 if (pd->pd_flags != PD_ELS_MARK) {
10368 10353 mutex_exit(&pd->pd_mutex);
10369 10354 continue;
10370 10355 }
10371 10356
10372 10357 dbg_count++;
10373 10358
10374 10359 /*
10375 10360 * If it is already marked deletion, nothing
10376 10361 * else to do.
10377 10362 */
10378 10363 if (pd->pd_type == PORT_DEVICE_DELETE) {
10379 10364 pd->pd_type = PORT_DEVICE_OLD;
10380 10365
10381 10366 mutex_exit(&pd->pd_mutex);
10382 10367 mutex_exit(&port->fp_mutex);
10383 10368 fp_jobdone(job);
10384 10369 mutex_enter(&port->fp_mutex);
10385 10370
10386 10371 continue;
10387 10372 }
10388 10373
10389 10374 /*
10390 10375 * If it is freshly discovered out of
10391 10376 * the orphan list, nothing else to do
10392 10377 */
10393 10378 if (pd->pd_type == PORT_DEVICE_NEW) {
10394 10379 pd->pd_flags = PD_IDLE;
10395 10380
10396 10381 mutex_exit(&pd->pd_mutex);
10397 10382 mutex_exit(&port->fp_mutex);
10398 10383 fp_jobdone(job);
10399 10384 mutex_enter(&port->fp_mutex);
10400 10385
10401 10386 continue;
10402 10387 }
10403 10388
10404 10389 pd->pd_flags = PD_IDLE;
10405 10390 d_id = pd->pd_port_id.port_id;
10406 10391
10407 10392 /*
10408 10393 * Explicitly mark all devices OLD; successful
10409 10394 * PLOGI should reset this to either NO_CHANGE
10410 10395 * or CHANGED.
10411 10396 */
10412 10397 if (pd->pd_type != PORT_DEVICE_CHANGED) {
10413 10398 pd->pd_type = PORT_DEVICE_OLD;
10414 10399 }
10415 10400
10416 10401 mutex_exit(&pd->pd_mutex);
10417 10402 mutex_exit(&port->fp_mutex);
10418 10403
10419 10404 rval = fp_port_login(port, d_id, job,
10420 10405 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10421 10406
10422 10407 if (rval != FC_SUCCESS) {
10423 10408 fp_jobdone(job);
10424 10409 }
10425 10410 mutex_enter(&port->fp_mutex);
10426 10411 }
10427 10412 }
10428 10413 mutex_exit(&port->fp_mutex);
10429 10414
10430 10415 ASSERT(dbg_count == count);
10431 10416 fp_jobwait(job);
10432 10417
10433 10418 mutex_enter(&port->fp_mutex);
10434 10419
10435 10420 ASSERT(port->fp_statec_busy > 0);
10436 10421 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10437 10422 if (port->fp_statec_busy > 1) {
10438 10423 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10439 10424 }
10440 10425 }
10441 10426 mutex_exit(&port->fp_mutex);
10442 10427 } else {
10443 10428 ASSERT(port->fp_statec_busy > 0);
10444 10429 if (port->fp_statec_busy > 1) {
10445 10430 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10446 10431 }
10447 10432 mutex_exit(&port->fp_mutex);
10448 10433 }
10449 10434
10450 10435 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10451 10436 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10452 10437
10453 10438 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10454 10439 listlen, listlen, KM_SLEEP);
10455 10440
10456 10441 mutex_enter(&port->fp_mutex);
10457 10442 } else {
10458 10443 ASSERT(changelist == NULL && listlen == 0);
10459 10444 mutex_enter(&port->fp_mutex);
10460 10445 if (--port->fp_statec_busy == 0) {
10461 10446 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10462 10447 }
10463 10448 }
10464 10449 }
10465 10450
10466 10451
10467 10452 /*
10468 10453 * Fill out device list for userland ioctl in private loop
10469 10454 */
10470 10455 static int
10471 10456 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10472 10457 {
10473 10458 int rval;
10474 10459 int count;
10475 10460 int index;
10476 10461 int num_devices;
10477 10462 fc_remote_node_t *node;
10478 10463 fc_port_dev_t *devlist;
10479 10464 int lilp_device_count;
10480 10465 fc_lilpmap_t *lilp_map;
10481 10466 uchar_t *alpa_list;
10482 10467
10483 10468 ASSERT(MUTEX_HELD(&port->fp_mutex));
10484 10469
10485 10470 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10486 10471 if (port->fp_total_devices > port->fp_dev_count &&
10487 10472 num_devices >= port->fp_total_devices) {
10488 10473 job_request_t *job;
10489 10474
10490 10475 mutex_exit(&port->fp_mutex);
10491 10476 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10492 10477 job->job_counter = 1;
10493 10478
10494 10479 mutex_enter(&port->fp_mutex);
10495 10480 fp_get_loopmap(port, job);
10496 10481 mutex_exit(&port->fp_mutex);
10497 10482
10498 10483 fp_jobwait(job);
10499 10484 fctl_dealloc_job(job);
10500 10485 } else {
10501 10486 mutex_exit(&port->fp_mutex);
10502 10487 }
10503 10488 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10504 10489
10505 10490 mutex_enter(&port->fp_mutex);
10506 10491
10507 10492 /*
10508 10493 * Applications are accustomed to getting the device list in
10509 10494 * LILP map order. The HBA firmware usually returns the device
10510 10495 * map in the LILP map order and diagnostic applications would
10511 10496 * prefer to receive in the device list in that order too
10512 10497 */
10513 10498 lilp_map = &port->fp_lilp_map;
10514 10499 alpa_list = &lilp_map->lilp_alpalist[0];
10515 10500
10516 10501 /*
10517 10502 * the length field corresponds to the offset in the LILP frame
10518 10503 * which begins with 1. The thing to note here is that the
10519 10504 * lilp_device_count is 1 more than fp->fp_total_devices since
10520 10505 * the host adapter's alpa also shows up in the lilp map. We
10521 10506 * don't however return details of the host adapter since
10522 10507 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10523 10508 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10524 10509 * ioctl to obtain details about the host adapter port.
10525 10510 */
10526 10511 lilp_device_count = lilp_map->lilp_length;
10527 10512
10528 10513 for (count = index = 0; index < lilp_device_count &&
10529 10514 count < num_devices; index++) {
10530 10515 uint32_t d_id;
10531 10516 fc_remote_port_t *pd;
10532 10517
10533 10518 d_id = alpa_list[index];
10534 10519
10535 10520 mutex_exit(&port->fp_mutex);
10536 10521 pd = fctl_get_remote_port_by_did(port, d_id);
10537 10522 mutex_enter(&port->fp_mutex);
10538 10523
10539 10524 if (pd != NULL) {
10540 10525 mutex_enter(&pd->pd_mutex);
10541 10526
10542 10527 if (pd->pd_state == PORT_DEVICE_INVALID) {
10543 10528 mutex_exit(&pd->pd_mutex);
10544 10529 continue;
10545 10530 }
10546 10531
10547 10532 devlist[count].dev_state = pd->pd_state;
10548 10533 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10549 10534 devlist[count].dev_did = pd->pd_port_id;
10550 10535 devlist[count].dev_did.priv_lilp_posit =
10551 10536 (uint8_t)(index & 0xff);
10552 10537 bcopy((caddr_t)pd->pd_fc4types,
10553 10538 (caddr_t)devlist[count].dev_type,
10554 10539 sizeof (pd->pd_fc4types));
10555 10540
10556 10541 bcopy((caddr_t)&pd->pd_port_name,
10557 10542 (caddr_t)&devlist[count].dev_pwwn,
10558 10543 sizeof (la_wwn_t));
10559 10544
10560 10545 node = pd->pd_remote_nodep;
10561 10546 mutex_exit(&pd->pd_mutex);
10562 10547
10563 10548 if (node) {
10564 10549 mutex_enter(&node->fd_mutex);
10565 10550 bcopy((caddr_t)&node->fd_node_name,
10566 10551 (caddr_t)&devlist[count].dev_nwwn,
10567 10552 sizeof (la_wwn_t));
10568 10553 mutex_exit(&node->fd_mutex);
10569 10554 }
10570 10555 count++;
10571 10556 }
10572 10557 }
10573 10558
10574 10559 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10575 10560 sizeof (count), mode)) {
10576 10561 rval = FC_FAILURE;
10577 10562 }
10578 10563
10579 10564 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10580 10565 sizeof (fc_port_dev_t) * num_devices, mode)) {
10581 10566 rval = FC_FAILURE;
10582 10567 } else {
10583 10568 rval = FC_SUCCESS;
10584 10569 }
10585 10570
10586 10571 kmem_free(devlist, sizeof (*devlist) * num_devices);
10587 10572 ASSERT(MUTEX_HELD(&port->fp_mutex));
10588 10573
10589 10574 return (rval);
10590 10575 }
10591 10576
10592 10577
10593 10578 /*
10594 10579 * Completion function for responses to unsolicited commands
10595 10580 */
10596 10581 static void
10597 10582 fp_unsol_intr(fc_packet_t *pkt)
10598 10583 {
10599 10584 fp_cmd_t *cmd;
10600 10585 fc_local_port_t *port;
10601 10586
10602 10587 cmd = pkt->pkt_ulp_private;
10603 10588 port = cmd->cmd_port;
10604 10589
10605 10590 mutex_enter(&port->fp_mutex);
10606 10591 port->fp_out_fpcmds--;
10607 10592 mutex_exit(&port->fp_mutex);
10608 10593
10609 10594 if (pkt->pkt_state != FC_PKT_SUCCESS) {
10610 10595 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10611 10596 "couldn't post response to unsolicited request;"
10612 10597 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10613 10598 pkt->pkt_resp_fhdr.rx_id);
10614 10599 }
10615 10600
10616 10601 if (cmd == port->fp_els_resp_pkt) {
10617 10602 mutex_enter(&port->fp_mutex);
10618 10603 port->fp_els_resp_pkt_busy = 0;
10619 10604 mutex_exit(&port->fp_mutex);
10620 10605 return;
10621 10606 }
10622 10607
10623 10608 fp_free_pkt(cmd);
10624 10609 }
10625 10610
10626 10611
10627 10612 /*
10628 10613 * solicited LINIT ELS completion function
10629 10614 */
10630 10615 static void
10631 10616 fp_linit_intr(fc_packet_t *pkt)
10632 10617 {
10633 10618 fp_cmd_t *cmd;
10634 10619 job_request_t *job;
10635 10620 fc_linit_resp_t acc;
10636 10621 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10637 10622
10638 10623 cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10639 10624
10640 10625 mutex_enter(&cmd->cmd_port->fp_mutex);
10641 10626 cmd->cmd_port->fp_out_fpcmds--;
10642 10627 mutex_exit(&cmd->cmd_port->fp_mutex);
10643 10628
10644 10629 if (FP_IS_PKT_ERROR(pkt)) {
10645 10630 (void) fp_common_intr(pkt, 1);
10646 10631 return;
10647 10632 }
10648 10633
10649 10634 job = cmd->cmd_job;
10650 10635
10651 10636 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10652 10637 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10653 10638 if (acc.status != FC_LINIT_SUCCESS) {
10654 10639 job->job_result = FC_FAILURE;
10655 10640 } else {
10656 10641 job->job_result = FC_SUCCESS;
10657 10642 }
10658 10643
10659 10644 fp_iodone(cmd);
10660 10645 }
10661 10646
10662 10647
10663 10648 /*
10664 10649 * Decode the unsolicited request; For FC-4 Device and Link data frames
10665 10650 * notify the registered ULP of this FC-4 type right here. For Unsolicited
10666 10651 * ELS requests, submit a request to the job_handler thread to work on it.
10667 10652 * The intent is to act quickly on the FC-4 unsolicited link and data frames
10668 10653 * and save much of the interrupt time processing of unsolicited ELS requests
10669 10654 * and hand it off to the job_handler thread.
10670 10655 */
10671 10656 static void
10672 10657 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10673 10658 {
10674 10659 uchar_t r_ctl;
10675 10660 uchar_t ls_code;
10676 10661 uint32_t s_id;
10677 10662 uint32_t rscn_count = FC_INVALID_RSCN_COUNT;
10678 10663 uint32_t cb_arg;
10679 10664 fp_cmd_t *cmd;
10680 10665 fc_local_port_t *port;
10681 10666 job_request_t *job;
10682 10667 fc_remote_port_t *pd;
10683 10668
10684 10669 port = port_handle;
10685 10670
10686 10671 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10687 10672 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10688 10673 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10689 10674 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10690 10675 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10691 10676 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10692 10677 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10693 10678 buf->ub_buffer[0]);
10694 10679
10695 10680 if (type & 0x80000000) {
10696 10681 /*
10697 10682 * Huh ? Nothing much can be done without
10698 10683 * a valid buffer. So just exit.
10699 10684 */
10700 10685 return;
10701 10686 }
10702 10687 /*
10703 10688 * If the unsolicited interrupts arrive while it isn't
10704 10689 * safe to handle unsolicited callbacks; Drop them, yes,
10705 10690 * drop them on the floor
10706 10691 */
10707 10692 mutex_enter(&port->fp_mutex);
10708 10693 port->fp_active_ubs++;
10709 10694 if ((port->fp_soft_state &
10710 10695 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10711 10696 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10712 10697
10713 10698 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10714 10699 "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10715 10700 "seq_id=%x, ox_id=%x, rx_id=%x"
10716 10701 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10717 10702 buf->ub_frame.type, buf->ub_frame.seq_id,
10718 10703 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10719 10704
10720 10705 ASSERT(port->fp_active_ubs > 0);
10721 10706 if (--(port->fp_active_ubs) == 0) {
10722 10707 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10723 10708 }
10724 10709
10725 10710 mutex_exit(&port->fp_mutex);
10726 10711
10727 10712 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10728 10713 1, &buf->ub_token);
10729 10714
10730 10715 return;
10731 10716 }
10732 10717
10733 10718 r_ctl = buf->ub_frame.r_ctl;
10734 10719 s_id = buf->ub_frame.s_id;
10735 10720 if (port->fp_active_ubs == 1) {
10736 10721 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10737 10722 }
10738 10723
10739 10724 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10740 10725 port->fp_statec_busy) {
10741 10726 mutex_exit(&port->fp_mutex);
10742 10727 pd = fctl_get_remote_port_by_did(port, s_id);
10743 10728 if (pd) {
10744 10729 mutex_enter(&pd->pd_mutex);
10745 10730 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10746 10731 FP_TRACE(FP_NHEAD1(3, 0),
10747 10732 "LOGO for LOGGED IN D_ID %x",
10748 10733 buf->ub_frame.s_id);
10749 10734 pd->pd_state = PORT_DEVICE_VALID;
10750 10735 }
10751 10736 mutex_exit(&pd->pd_mutex);
10752 10737 }
10753 10738
10754 10739 mutex_enter(&port->fp_mutex);
10755 10740 ASSERT(port->fp_active_ubs > 0);
10756 10741 if (--(port->fp_active_ubs) == 0) {
10757 10742 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10758 10743 }
10759 10744 mutex_exit(&port->fp_mutex);
10760 10745
10761 10746 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10762 10747 1, &buf->ub_token);
10763 10748
10764 10749 FP_TRACE(FP_NHEAD1(3, 0),
10765 10750 "fp_unsol_cb() bailing out LOGO for D_ID %x",
10766 10751 buf->ub_frame.s_id);
10767 10752 return;
10768 10753 }
10769 10754
10770 10755 if (port->fp_els_resp_pkt_busy == 0) {
10771 10756 if (r_ctl == R_CTL_ELS_REQ) {
10772 10757 ls_code = buf->ub_buffer[0];
10773 10758
10774 10759 switch (ls_code) {
10775 10760 case LA_ELS_PLOGI:
10776 10761 case LA_ELS_FLOGI:
10777 10762 port->fp_els_resp_pkt_busy = 1;
10778 10763 mutex_exit(&port->fp_mutex);
10779 10764 fp_i_handle_unsol_els(port, buf);
10780 10765
10781 10766 mutex_enter(&port->fp_mutex);
10782 10767 ASSERT(port->fp_active_ubs > 0);
10783 10768 if (--(port->fp_active_ubs) == 0) {
10784 10769 port->fp_soft_state &=
10785 10770 ~FP_SOFT_IN_UNSOL_CB;
10786 10771 }
10787 10772 mutex_exit(&port->fp_mutex);
10788 10773 port->fp_fca_tran->fca_ub_release(
10789 10774 port->fp_fca_handle, 1, &buf->ub_token);
10790 10775
10791 10776 return;
10792 10777 case LA_ELS_RSCN:
10793 10778 if (++(port)->fp_rscn_count ==
10794 10779 FC_INVALID_RSCN_COUNT) {
10795 10780 ++(port)->fp_rscn_count;
10796 10781 }
10797 10782 rscn_count = port->fp_rscn_count;
10798 10783 break;
10799 10784
10800 10785 default:
10801 10786 break;
10802 10787 }
10803 10788 }
10804 10789 } else if ((r_ctl == R_CTL_ELS_REQ) &&
10805 10790 (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10806 10791 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10807 10792 ++port->fp_rscn_count;
10808 10793 }
10809 10794 rscn_count = port->fp_rscn_count;
10810 10795 }
10811 10796
10812 10797 mutex_exit(&port->fp_mutex);
10813 10798
10814 10799 switch (r_ctl & R_CTL_ROUTING) {
10815 10800 case R_CTL_DEVICE_DATA:
10816 10801 /*
10817 10802 * If the unsolicited buffer is a CT IU,
10818 10803 * have the job_handler thread work on it.
10819 10804 */
10820 10805 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10821 10806 break;
10822 10807 }
10823 10808 /* FALLTHROUGH */
10824 10809
10825 10810 case R_CTL_FC4_SVC: {
10826 10811 int sendup = 0;
10827 10812
10828 10813 /*
10829 10814 * If a LOGIN isn't performed before this request
10830 10815 * shut the door on this port with a reply that a
10831 10816 * LOGIN is required. We make an exception however
10832 10817 * for IP broadcast packets and pass them through
10833 10818 * to the IP ULP(s) to handle broadcast requests.
10834 10819 * This is not a problem for private loop devices
10835 10820 * but for fabric topologies we don't log into the
10836 10821 * remote ports during port initialization and
10837 10822 * the ULPs need to log into requesting ports on
10838 10823 * demand.
10839 10824 */
10840 10825 pd = fctl_get_remote_port_by_did(port, s_id);
10841 10826 if (pd) {
10842 10827 mutex_enter(&pd->pd_mutex);
10843 10828 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10844 10829 sendup++;
10845 10830 }
10846 10831 mutex_exit(&pd->pd_mutex);
10847 10832 } else if ((pd == NULL) &&
10848 10833 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10849 10834 (buf->ub_frame.d_id == 0xffffff ||
10850 10835 buf->ub_frame.d_id == 0x00)) {
10851 10836 /* brodacst IP frame - so sendup via job thread */
10852 10837 break;
10853 10838 }
10854 10839
10855 10840 /*
10856 10841 * Send all FC4 services via job thread too
10857 10842 */
10858 10843 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10859 10844 break;
10860 10845 }
10861 10846
10862 10847 if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10863 10848 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10864 10849 return;
10865 10850 }
10866 10851
10867 10852 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10868 10853 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10869 10854 0, KM_NOSLEEP, pd);
10870 10855 if (cmd != NULL) {
10871 10856 fp_els_rjt_init(port, cmd, buf,
10872 10857 FC_ACTION_NON_RETRYABLE,
10873 10858 FC_REASON_LOGIN_REQUIRED, NULL);
10874 10859
10875 10860 if (fp_sendcmd(port, cmd,
10876 10861 port->fp_fca_handle) != FC_SUCCESS) {
10877 10862 fp_free_pkt(cmd);
10878 10863 }
10879 10864 }
10880 10865 }
10881 10866
10882 10867 mutex_enter(&port->fp_mutex);
10883 10868 ASSERT(port->fp_active_ubs > 0);
10884 10869 if (--(port->fp_active_ubs) == 0) {
10885 10870 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10886 10871 }
10887 10872 mutex_exit(&port->fp_mutex);
10888 10873 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10889 10874 1, &buf->ub_token);
10890 10875
10891 10876 return;
10892 10877 }
10893 10878
10894 10879 default:
10895 10880 break;
10896 10881 }
10897 10882
10898 10883 /*
10899 10884 * Submit a Request to the job_handler thread to work
10900 10885 * on the unsolicited request. The potential side effect
10901 10886 * of this is that the unsolicited buffer takes a little
10902 10887 * longer to get released but we save interrupt time in
10903 10888 * the bargain.
10904 10889 */
10905 10890 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10906 10891
10907 10892 /*
10908 10893 * One way that the rscn_count will get used is described below :
10909 10894 *
10910 10895 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10911 10896 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10912 10897 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10913 10898 * by overloading the job_cb_arg to pass the rscn_count
10914 10899 * 4. When one of the routines processing the RSCN picks it up (ex:
10915 10900 * fp_validate_rscn_page()), it passes this count in the map
10916 10901 * structure (as part of the map_rscn_info structure member) to the
10917 10902 * ULPs.
10918 10903 * 5. When ULPs make calls back to the transport (example interfaces for
10919 10904 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10920 10905 * can now pass back this count as part of the fc_packet's
10921 10906 * pkt_ulp_rscn_count member. fcp does this currently.
10922 10907 * 6. When transport gets a call to transport a command on the wire, it
10923 10908 * will check to see if there is a valid pkt_ulp_rsvd1 field in the
10924 10909 * fc_packet. If there is, it will match that info with the current
10925 10910 * rscn_count on that instance of the port. If they don't match up
10926 10911 * then there was a newer RSCN. The ULP gets back an error code which
10927 10912 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10928 10913 * 7. At this point the ULP is free to make up its own mind as to how to
10929 10914 * handle this. Currently, fcp will reset its retry counters and keep
10930 10915 * retrying the operation it was doing in anticipation of getting a
10931 10916 * new state change call back for the new RSCN.
10932 10917 */
10933 10918 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10934 10919 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10935 10920 if (job == NULL) {
10936 10921 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10937 10922 "couldn't submit a job to the thread, failing..");
10938 10923
10939 10924 mutex_enter(&port->fp_mutex);
10940 10925
10941 10926 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10942 10927 --port->fp_rscn_count;
10943 10928 }
10944 10929
10945 10930 ASSERT(port->fp_active_ubs > 0);
10946 10931 if (--(port->fp_active_ubs) == 0) {
10947 10932 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10948 10933 }
10949 10934
10950 10935 mutex_exit(&port->fp_mutex);
10951 10936 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10952 10937 1, &buf->ub_token);
10953 10938
10954 10939 return;
10955 10940 }
10956 10941 job->job_private = (void *)buf;
10957 10942 fctl_enque_job(port, job);
10958 10943 }
10959 10944
10960 10945
10961 10946 /*
10962 10947 * Handle unsolicited requests
10963 10948 */
10964 10949 static void
10965 10950 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10966 10951 job_request_t *job)
10967 10952 {
10968 10953 uchar_t r_ctl;
10969 10954 uchar_t ls_code;
10970 10955 uint32_t s_id;
10971 10956 fp_cmd_t *cmd;
10972 10957 fc_remote_port_t *pd;
10973 10958 fp_unsol_spec_t *ub_spec;
10974 10959
10975 10960 r_ctl = buf->ub_frame.r_ctl;
10976 10961 s_id = buf->ub_frame.s_id;
10977 10962
10978 10963 switch (r_ctl & R_CTL_ROUTING) {
10979 10964 case R_CTL_EXTENDED_SVC:
10980 10965 if (r_ctl != R_CTL_ELS_REQ) {
10981 10966 break;
10982 10967 }
10983 10968
10984 10969 ls_code = buf->ub_buffer[0];
10985 10970 switch (ls_code) {
10986 10971 case LA_ELS_LOGO:
10987 10972 case LA_ELS_ADISC:
10988 10973 case LA_ELS_PRLO:
10989 10974 pd = fctl_get_remote_port_by_did(port, s_id);
10990 10975 if (pd == NULL) {
10991 10976 if (!FC_IS_REAL_DEVICE(s_id)) {
10992 10977 break;
10993 10978 }
10994 10979 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10995 10980 break;
10996 10981 }
10997 10982 if ((cmd = fp_alloc_pkt(port,
10998 10983 sizeof (la_els_rjt_t), 0, KM_SLEEP,
10999 10984 NULL)) == NULL) {
11000 10985 /*
11001 10986 * Can this actually fail when
11002 10987 * given KM_SLEEP? (Could be used
11003 10988 * this way in a number of places.)
11004 10989 */
11005 10990 break;
11006 10991 }
11007 10992
11008 10993 fp_els_rjt_init(port, cmd, buf,
11009 10994 FC_ACTION_NON_RETRYABLE,
11010 10995 FC_REASON_INVALID_LINK_CTRL, job);
11011 10996
11012 10997 if (fp_sendcmd(port, cmd,
11013 10998 port->fp_fca_handle) != FC_SUCCESS) {
11014 10999 fp_free_pkt(cmd);
11015 11000 }
11016 11001
11017 11002 break;
11018 11003 }
11019 11004 if (ls_code == LA_ELS_LOGO) {
11020 11005 fp_handle_unsol_logo(port, buf, pd, job);
11021 11006 } else if (ls_code == LA_ELS_ADISC) {
11022 11007 fp_handle_unsol_adisc(port, buf, pd, job);
11023 11008 } else {
11024 11009 fp_handle_unsol_prlo(port, buf, pd, job);
11025 11010 }
11026 11011 break;
11027 11012
11028 11013 case LA_ELS_PLOGI:
11029 11014 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
11030 11015 break;
11031 11016
11032 11017 case LA_ELS_FLOGI:
11033 11018 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
11034 11019 break;
11035 11020
11036 11021 case LA_ELS_RSCN:
11037 11022 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
11038 11023 break;
11039 11024
11040 11025 default:
11041 11026 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11042 11027 ub_spec->port = port;
11043 11028 ub_spec->buf = buf;
11044 11029
11045 11030 (void) taskq_dispatch(port->fp_taskq,
11046 11031 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11047 11032 return;
11048 11033 }
11049 11034 break;
11050 11035
11051 11036 case R_CTL_BASIC_SVC:
11052 11037 /*
11053 11038 * The unsolicited basic link services could be ABTS
11054 11039 * and RMC (Or even a NOP). Just BA_RJT them until
11055 11040 * such time there arises a need to handle them more
11056 11041 * carefully.
11057 11042 */
11058 11043 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11059 11044 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
11060 11045 0, KM_SLEEP, NULL);
11061 11046 if (cmd != NULL) {
11062 11047 fp_ba_rjt_init(port, cmd, buf, job);
11063 11048 if (fp_sendcmd(port, cmd,
11064 11049 port->fp_fca_handle) != FC_SUCCESS) {
11065 11050 fp_free_pkt(cmd);
11066 11051 }
11067 11052 }
11068 11053 }
11069 11054 break;
11070 11055
11071 11056 case R_CTL_DEVICE_DATA:
11072 11057 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11073 11058 /*
11074 11059 * Mostly this is of type FC_TYPE_FC_SERVICES.
11075 11060 * As we don't like any Unsolicited FC services
11076 11061 * requests, we would do well to RJT them as
11077 11062 * well.
11078 11063 */
11079 11064 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11080 11065 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11081 11066 0, KM_SLEEP, NULL);
11082 11067 if (cmd != NULL) {
11083 11068 fp_els_rjt_init(port, cmd, buf,
11084 11069 FC_ACTION_NON_RETRYABLE,
11085 11070 FC_REASON_INVALID_LINK_CTRL, job);
11086 11071
11087 11072 if (fp_sendcmd(port, cmd,
11088 11073 port->fp_fca_handle) !=
11089 11074 FC_SUCCESS) {
11090 11075 fp_free_pkt(cmd);
11091 11076 }
11092 11077 }
11093 11078 }
11094 11079 break;
11095 11080 }
11096 11081 /* FALLTHROUGH */
11097 11082
11098 11083 case R_CTL_FC4_SVC:
11099 11084 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11100 11085 ub_spec->port = port;
11101 11086 ub_spec->buf = buf;
11102 11087
11103 11088 (void) taskq_dispatch(port->fp_taskq,
11104 11089 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11105 11090 return;
11106 11091
11107 11092 case R_CTL_LINK_CTL:
11108 11093 /*
11109 11094 * Turn deaf ear on unsolicited link control frames.
11110 11095 * Typical unsolicited link control Frame is an LCR
11111 11096 * (to reset End to End credit to the default login
11112 11097 * value and abort current sequences for all classes)
11113 11098 * An intelligent microcode/firmware should handle
11114 11099 * this transparently at its level and not pass all
11115 11100 * the way up here.
11116 11101 *
11117 11102 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11118 11103 * or F_BSY. P_RJT is chosen to be the most appropriate
11119 11104 * at this time.
11120 11105 */
11121 11106 /* FALLTHROUGH */
11122 11107
11123 11108 default:
11124 11109 /*
11125 11110 * Just reject everything else as an invalid request.
11126 11111 */
11127 11112 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11128 11113 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11129 11114 0, KM_SLEEP, NULL);
11130 11115 if (cmd != NULL) {
11131 11116 fp_els_rjt_init(port, cmd, buf,
11132 11117 FC_ACTION_NON_RETRYABLE,
11133 11118 FC_REASON_INVALID_LINK_CTRL, job);
11134 11119
11135 11120 if (fp_sendcmd(port, cmd,
11136 11121 port->fp_fca_handle) != FC_SUCCESS) {
11137 11122 fp_free_pkt(cmd);
11138 11123 }
11139 11124 }
11140 11125 }
11141 11126 break;
11142 11127 }
11143 11128
11144 11129 mutex_enter(&port->fp_mutex);
11145 11130 ASSERT(port->fp_active_ubs > 0);
11146 11131 if (--(port->fp_active_ubs) == 0) {
11147 11132 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11148 11133 }
11149 11134 mutex_exit(&port->fp_mutex);
11150 11135 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11151 11136 1, &buf->ub_token);
11152 11137 }
11153 11138
11154 11139
11155 11140 /*
11156 11141 * Prepare a BA_RJT and send it over.
11157 11142 */
11158 11143 static void
11159 11144 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11160 11145 job_request_t *job)
11161 11146 {
11162 11147 fc_packet_t *pkt;
11163 11148 la_ba_rjt_t payload;
11164 11149
11165 11150 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11166 11151
11167 11152 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11168 11153 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11169 11154 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11170 11155 cmd->cmd_retry_count = 1;
11171 11156 cmd->cmd_ulp_pkt = NULL;
11172 11157
11173 11158 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11174 11159 cmd->cmd_job = job;
11175 11160
11176 11161 pkt = &cmd->cmd_pkt;
11177 11162
11178 11163 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11179 11164
11180 11165 payload.reserved = 0;
11181 11166 payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11182 11167 payload.explanation = FC_EXPLN_NONE;
11183 11168 payload.vendor = 0;
11184 11169
11185 11170 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11186 11171 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11187 11172 }
11188 11173
11189 11174
11190 11175 /*
11191 11176 * Prepare an LS_RJT and send it over
11192 11177 */
11193 11178 static void
11194 11179 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11195 11180 uchar_t action, uchar_t reason, job_request_t *job)
11196 11181 {
11197 11182 fc_packet_t *pkt;
11198 11183 la_els_rjt_t payload;
11199 11184
11200 11185 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11201 11186
11202 11187 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11203 11188 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11204 11189 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11205 11190 cmd->cmd_retry_count = 1;
11206 11191 cmd->cmd_ulp_pkt = NULL;
11207 11192
11208 11193 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11209 11194 cmd->cmd_job = job;
11210 11195
11211 11196 pkt = &cmd->cmd_pkt;
11212 11197
11213 11198 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11214 11199
11215 11200 payload.ls_code.ls_code = LA_ELS_RJT;
11216 11201 payload.ls_code.mbz = 0;
11217 11202 payload.action = action;
11218 11203 payload.reason = reason;
11219 11204 payload.reserved = 0;
11220 11205 payload.vu = 0;
11221 11206
11222 11207 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11223 11208 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11224 11209 }
11225 11210
11226 11211 /*
11227 11212 * Function: fp_prlo_acc_init
11228 11213 *
11229 11214 * Description: Initializes an Link Service Accept for a PRLO.
11230 11215 *
11231 11216 * Arguments: *port Local port through which the PRLO was
11232 11217 * received.
11233 11218 * cmd Command that will carry the accept.
11234 11219 * *buf Unsolicited buffer containing the PRLO
11235 11220 * request.
11236 11221 * job Job request.
11237 11222 * sleep Allocation mode.
11238 11223 *
11239 11224 * Return Value: *cmd Command containing the response.
11240 11225 *
11241 11226 * Context: Depends on the parameter sleep.
11242 11227 */
11243 11228 fp_cmd_t *
11244 11229 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11245 11230 fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11246 11231 {
11247 11232 fp_cmd_t *cmd;
11248 11233 fc_packet_t *pkt;
11249 11234 la_els_prlo_t *req;
11250 11235 size_t len;
11251 11236 uint16_t flags;
11252 11237
11253 11238 req = (la_els_prlo_t *)buf->ub_buffer;
11254 11239 len = (size_t)ntohs(req->payload_length);
11255 11240
11256 11241 /*
11257 11242 * The payload of the accept to a PRLO has to be the exact match of
11258 11243 * the payload of the request (at the exception of the code).
11259 11244 */
11260 11245 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11261 11246
11262 11247 if (cmd) {
11263 11248 /*
11264 11249 * The fp command was successfully allocated.
11265 11250 */
11266 11251 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11267 11252 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11268 11253 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11269 11254 cmd->cmd_retry_count = 1;
11270 11255 cmd->cmd_ulp_pkt = NULL;
11271 11256
11272 11257 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11273 11258 cmd->cmd_job = job;
11274 11259
11275 11260 pkt = &cmd->cmd_pkt;
11276 11261
11277 11262 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11278 11263 FC_TYPE_EXTENDED_LS);
11279 11264
11280 11265 /* The code is overwritten for the copy. */
11281 11266 req->ls_code = LA_ELS_ACC;
11282 11267 /* Response code is set. */
11283 11268 flags = ntohs(req->flags);
11284 11269 flags &= ~SP_RESP_CODE_MASK;
11285 11270 flags |= SP_RESP_CODE_REQ_EXECUTED;
11286 11271 req->flags = htons(flags);
11287 11272
11288 11273 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11289 11274 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11290 11275 }
11291 11276 return (cmd);
11292 11277 }
11293 11278
11294 11279 /*
11295 11280 * Prepare an ACC response to an ELS request
11296 11281 */
11297 11282 static void
11298 11283 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11299 11284 job_request_t *job)
11300 11285 {
11301 11286 fc_packet_t *pkt;
11302 11287 ls_code_t payload;
11303 11288
11304 11289 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11305 11290 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11306 11291 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11307 11292 cmd->cmd_retry_count = 1;
11308 11293 cmd->cmd_ulp_pkt = NULL;
11309 11294
11310 11295 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11311 11296 cmd->cmd_job = job;
11312 11297
11313 11298 pkt = &cmd->cmd_pkt;
11314 11299
11315 11300 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11316 11301
11317 11302 payload.ls_code = LA_ELS_ACC;
11318 11303 payload.mbz = 0;
11319 11304
11320 11305 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11321 11306 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11322 11307 }
11323 11308
11324 11309 /*
11325 11310 * Unsolicited PRLO handler
11326 11311 *
11327 11312 * A Process Logout should be handled by the ULP that established it. However,
11328 11313 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens
11329 11314 * when a device implicitly logs out an initiator (for whatever reason) and
11330 11315 * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11331 11316 * The logical thing to do for the device would be to send a LOGO in response
11332 11317 * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11333 11318 * a PRLO instead.
11334 11319 *
11335 11320 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11336 11321 * think that the Port Login has been lost. If we follow the Fibre Channel
11337 11322 * protocol to the letter a PRLI should be sent after accepting the PRLO. If
11338 11323 * the Port Login has also been lost, the remote port will reject the PRLI
11339 11324 * indicating that we must PLOGI first. The initiator will then turn around and
11340 11325 * send a PLOGI. The way Leadville is layered and the way the ULP interface
11341 11326 * is defined doesn't allow this scenario to be followed easily. If FCP were to
11342 11327 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11343 11328 * needed would be received by FCP. FCP would have, then, to tell the transport
11344 11329 * (fp) to PLOGI. The problem is, the transport would still think the Port
11345 11330 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11346 11331 * if you think it's not necessary". To work around that difficulty, the PRLO
11347 11332 * is treated by the transport as a LOGO. The downside to it is a Port Login
11348 11333 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11349 11334 * has nothing to do with the PRLO) may be impacted. However, this is a
11350 11335 * scenario very unlikely to happen. As of today the only ULP in Leadville
11351 11336 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be
11352 11337 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11353 11338 * unlikely).
11354 11339 */
11355 11340 static void
11356 11341 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11357 11342 fc_remote_port_t *pd, job_request_t *job)
11358 11343 {
11359 11344 int busy;
11360 11345 int rval;
11361 11346 int retain;
11362 11347 fp_cmd_t *cmd;
11363 11348 fc_portmap_t *listptr;
11364 11349 boolean_t tolerance;
11365 11350 la_els_prlo_t *req;
11366 11351
11367 11352 req = (la_els_prlo_t *)buf->ub_buffer;
11368 11353
11369 11354 if ((ntohs(req->payload_length) !=
11370 11355 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11371 11356 (req->page_length != sizeof (service_parameter_page_t))) {
11372 11357 /*
11373 11358 * We are being very restrictive. Only on page per
11374 11359 * payload. If it is not the case we reject the ELS although
11375 11360 * we should reply indicating we handle only single page
11376 11361 * per PRLO.
11377 11362 */
11378 11363 goto fp_reject_prlo;
11379 11364 }
11380 11365
11381 11366 if (ntohs(req->payload_length) > buf->ub_bufsize) {
11382 11367 /*
11383 11368 * This is in case the payload advertizes a size bigger than
11384 11369 * what it really is.
11385 11370 */
11386 11371 goto fp_reject_prlo;
11387 11372 }
11388 11373
11389 11374 mutex_enter(&port->fp_mutex);
11390 11375 busy = port->fp_statec_busy;
11391 11376 mutex_exit(&port->fp_mutex);
11392 11377
11393 11378 mutex_enter(&pd->pd_mutex);
11394 11379 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11395 11380 if (!busy) {
11396 11381 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11397 11382 pd->pd_state == PORT_DEVICE_INVALID ||
11398 11383 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11399 11384 pd->pd_type == PORT_DEVICE_OLD) {
11400 11385 busy++;
11401 11386 }
11402 11387 }
11403 11388
11404 11389 if (busy) {
11405 11390 mutex_exit(&pd->pd_mutex);
11406 11391
11407 11392 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11408 11393 "pd=%p - busy",
11409 11394 pd->pd_port_id.port_id, pd);
11410 11395
11411 11396 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11412 11397 goto fp_reject_prlo;
11413 11398 }
11414 11399 } else {
11415 11400 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11416 11401
11417 11402 if (tolerance) {
11418 11403 fctl_tc_reset(&pd->pd_logo_tc);
11419 11404 retain = 0;
11420 11405 pd->pd_state = PORT_DEVICE_INVALID;
11421 11406 }
11422 11407
11423 11408 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11424 11409 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11425 11410 tolerance, retain);
11426 11411
11427 11412 pd->pd_aux_flags |= PD_LOGGED_OUT;
11428 11413 mutex_exit(&pd->pd_mutex);
11429 11414
11430 11415 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11431 11416 if (cmd == NULL) {
11432 11417 return;
11433 11418 }
11434 11419
11435 11420 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11436 11421 if (rval != FC_SUCCESS) {
11437 11422 fp_free_pkt(cmd);
11438 11423 return;
11439 11424 }
11440 11425
11441 11426 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11442 11427
11443 11428 if (retain) {
11444 11429 fp_unregister_login(pd);
11445 11430 fctl_copy_portmap(listptr, pd);
11446 11431 } else {
11447 11432 uint32_t d_id;
11448 11433 char ww_name[17];
11449 11434
11450 11435 mutex_enter(&pd->pd_mutex);
11451 11436 d_id = pd->pd_port_id.port_id;
11452 11437 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11453 11438 mutex_exit(&pd->pd_mutex);
11454 11439
11455 11440 FP_TRACE(FP_NHEAD2(9, 0),
11456 11441 "N_x Port with D_ID=%x, PWWN=%s logged out"
11457 11442 " %d times in %d us; Giving up", d_id, ww_name,
11458 11443 FC_LOGO_TOLERANCE_LIMIT,
11459 11444 FC_LOGO_TOLERANCE_TIME_LIMIT);
11460 11445
11461 11446 fp_fillout_old_map(listptr, pd, 0);
11462 11447 listptr->map_type = PORT_DEVICE_OLD;
11463 11448 }
11464 11449
11465 11450 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11466 11451 return;
11467 11452 }
11468 11453
11469 11454 fp_reject_prlo:
11470 11455
11471 11456 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11472 11457 if (cmd != NULL) {
11473 11458 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11474 11459 FC_REASON_INVALID_LINK_CTRL, job);
11475 11460
11476 11461 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11477 11462 fp_free_pkt(cmd);
11478 11463 }
11479 11464 }
11480 11465 }
11481 11466
11482 11467 /*
11483 11468 * Unsolicited LOGO handler
11484 11469 */
11485 11470 static void
11486 11471 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11487 11472 fc_remote_port_t *pd, job_request_t *job)
11488 11473 {
11489 11474 int busy;
11490 11475 int rval;
11491 11476 int retain;
11492 11477 fp_cmd_t *cmd;
11493 11478 fc_portmap_t *listptr;
11494 11479 boolean_t tolerance;
11495 11480
11496 11481 mutex_enter(&port->fp_mutex);
11497 11482 busy = port->fp_statec_busy;
11498 11483 mutex_exit(&port->fp_mutex);
11499 11484
11500 11485 mutex_enter(&pd->pd_mutex);
11501 11486 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11502 11487 if (!busy) {
11503 11488 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11504 11489 pd->pd_state == PORT_DEVICE_INVALID ||
11505 11490 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11506 11491 pd->pd_type == PORT_DEVICE_OLD) {
11507 11492 busy++;
11508 11493 }
11509 11494 }
11510 11495
11511 11496 if (busy) {
11512 11497 mutex_exit(&pd->pd_mutex);
11513 11498
11514 11499 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11515 11500 "pd=%p - busy",
11516 11501 pd->pd_port_id.port_id, pd);
11517 11502
11518 11503 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11519 11504 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11520 11505 0, KM_SLEEP, pd);
11521 11506 if (cmd != NULL) {
11522 11507 fp_els_rjt_init(port, cmd, buf,
11523 11508 FC_ACTION_NON_RETRYABLE,
11524 11509 FC_REASON_INVALID_LINK_CTRL, job);
11525 11510
11526 11511 if (fp_sendcmd(port, cmd,
11527 11512 port->fp_fca_handle) != FC_SUCCESS) {
11528 11513 fp_free_pkt(cmd);
11529 11514 }
11530 11515 }
11531 11516 }
11532 11517 } else {
11533 11518 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11534 11519
11535 11520 if (tolerance) {
11536 11521 fctl_tc_reset(&pd->pd_logo_tc);
11537 11522 retain = 0;
11538 11523 pd->pd_state = PORT_DEVICE_INVALID;
11539 11524 }
11540 11525
11541 11526 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11542 11527 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11543 11528 tolerance, retain);
11544 11529
11545 11530 pd->pd_aux_flags |= PD_LOGGED_OUT;
11546 11531 mutex_exit(&pd->pd_mutex);
11547 11532
11548 11533 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11549 11534 KM_SLEEP, pd);
11550 11535 if (cmd == NULL) {
11551 11536 return;
11552 11537 }
11553 11538
11554 11539 fp_els_acc_init(port, cmd, buf, job);
11555 11540
11556 11541 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11557 11542 if (rval != FC_SUCCESS) {
11558 11543 fp_free_pkt(cmd);
11559 11544 return;
11560 11545 }
11561 11546
11562 11547 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11563 11548
11564 11549 if (retain) {
11565 11550 job_request_t *job;
11566 11551 fctl_ns_req_t *ns_cmd;
11567 11552
11568 11553 /*
11569 11554 * when get LOGO, first try to get PID from nameserver
11570 11555 * if failed, then we do not need
11571 11556 * send PLOGI to that remote port
11572 11557 */
11573 11558 job = fctl_alloc_job(
11574 11559 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11575 11560
11576 11561 if (job != NULL) {
11577 11562 ns_cmd = fctl_alloc_ns_cmd(
11578 11563 sizeof (ns_req_gid_pn_t),
11579 11564 sizeof (ns_resp_gid_pn_t),
11580 11565 sizeof (ns_resp_gid_pn_t),
11581 11566 0, KM_SLEEP);
11582 11567 if (ns_cmd != NULL) {
11583 11568 int ret;
11584 11569 job->job_result = FC_SUCCESS;
11585 11570 ns_cmd->ns_cmd_code = NS_GID_PN;
11586 11571 ((ns_req_gid_pn_t *)
11587 11572 (ns_cmd->ns_cmd_buf))->pwwn =
11588 11573 pd->pd_port_name;
11589 11574 ret = fp_ns_query(
11590 11575 port, ns_cmd, job, 1, KM_SLEEP);
11591 11576 if ((ret != FC_SUCCESS) ||
11592 11577 (job->job_result != FC_SUCCESS)) {
11593 11578 fctl_free_ns_cmd(ns_cmd);
11594 11579 fctl_dealloc_job(job);
11595 11580 FP_TRACE(FP_NHEAD2(9, 0),
11596 11581 "NS query failed,",
11597 11582 " delete pd");
11598 11583 goto delete_pd;
11599 11584 }
11600 11585 fctl_free_ns_cmd(ns_cmd);
11601 11586 }
11602 11587 fctl_dealloc_job(job);
11603 11588 }
11604 11589 fp_unregister_login(pd);
11605 11590 fctl_copy_portmap(listptr, pd);
11606 11591 } else {
11607 11592 uint32_t d_id;
11608 11593 char ww_name[17];
11609 11594
11610 11595 delete_pd:
11611 11596 mutex_enter(&pd->pd_mutex);
11612 11597 d_id = pd->pd_port_id.port_id;
11613 11598 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11614 11599 mutex_exit(&pd->pd_mutex);
11615 11600
11616 11601 FP_TRACE(FP_NHEAD2(9, 0),
11617 11602 "N_x Port with D_ID=%x, PWWN=%s logged out"
11618 11603 " %d times in %d us; Giving up", d_id, ww_name,
11619 11604 FC_LOGO_TOLERANCE_LIMIT,
11620 11605 FC_LOGO_TOLERANCE_TIME_LIMIT);
11621 11606
11622 11607 fp_fillout_old_map(listptr, pd, 0);
11623 11608 listptr->map_type = PORT_DEVICE_OLD;
11624 11609 }
11625 11610
11626 11611 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11627 11612 }
11628 11613 }
11629 11614
11630 11615
11631 11616 /*
11632 11617 * Perform general purpose preparation of a response to an unsolicited request
11633 11618 */
11634 11619 static void
11635 11620 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11636 11621 uchar_t r_ctl, uchar_t type)
11637 11622 {
11638 11623 pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11639 11624 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11640 11625 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11641 11626 pkt->pkt_cmd_fhdr.type = type;
11642 11627 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11643 11628 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11644 11629 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl;
11645 11630 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11646 11631 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11647 11632 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11648 11633 pkt->pkt_cmd_fhdr.ro = 0;
11649 11634 pkt->pkt_cmd_fhdr.rsvd = 0;
11650 11635 pkt->pkt_comp = fp_unsol_intr;
11651 11636 pkt->pkt_timeout = FP_ELS_TIMEOUT;
11652 11637 pkt->pkt_ub_resp_token = (opaque_t)buf;
11653 11638 }
11654 11639
11655 11640 /*
11656 11641 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11657 11642 * early development days of public loop soc+ firmware, numerous problems
11658 11643 * were encountered (the details are undocumented and history now) which
11659 11644 * led to the birth of this function.
11660 11645 *
11661 11646 * If a pre-allocated unsolicited response packet is free, send out an
11662 11647 * immediate response, otherwise submit the request to the port thread
11663 11648 * to do the deferred processing.
11664 11649 */
11665 11650 static void
11666 11651 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11667 11652 {
11668 11653 int sent;
11669 11654 int f_port;
11670 11655 int do_acc;
11671 11656 fp_cmd_t *cmd;
11672 11657 la_els_logi_t *payload;
11673 11658 fc_remote_port_t *pd;
11674 11659 char dww_name[17];
11675 11660
11676 11661 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11677 11662
11678 11663 cmd = port->fp_els_resp_pkt;
11679 11664
11680 11665 mutex_enter(&port->fp_mutex);
11681 11666 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11682 11667 mutex_exit(&port->fp_mutex);
11683 11668
11684 11669 switch (buf->ub_buffer[0]) {
11685 11670 case LA_ELS_PLOGI: {
11686 11671 int small;
11687 11672
11688 11673 payload = (la_els_logi_t *)buf->ub_buffer;
11689 11674
11690 11675 f_port = FP_IS_F_PORT(payload->
11691 11676 common_service.cmn_features) ? 1 : 0;
11692 11677
11693 11678 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11694 11679 &payload->nport_ww_name);
11695 11680 pd = fctl_get_remote_port_by_pwwn(port,
11696 11681 &payload->nport_ww_name);
11697 11682 if (pd) {
11698 11683 mutex_enter(&pd->pd_mutex);
11699 11684 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11700 11685 /*
11701 11686 * Most likely this means a cross login is in
11702 11687 * progress or a device about to be yanked out.
11703 11688 * Only accept the plogi if my wwn is smaller.
11704 11689 */
11705 11690 if (pd->pd_type == PORT_DEVICE_OLD) {
11706 11691 sent = 1;
11707 11692 }
11708 11693 /*
11709 11694 * Stop plogi request (if any)
11710 11695 * attempt from local side to speedup
11711 11696 * the discovery progress.
11712 11697 * Mark the pd as PD_PLOGI_RECEPIENT.
11713 11698 */
11714 11699 if (f_port == 0 && small < 0) {
11715 11700 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11716 11701 }
11717 11702 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11718 11703
11719 11704 mutex_exit(&pd->pd_mutex);
11720 11705
11721 11706 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11722 11707 "Unsol PLOGI received. PD still exists in the "
11723 11708 "PWWN list. pd=%p PWWN=%s, sent=%x",
11724 11709 pd, dww_name, sent);
11725 11710
11726 11711 if (f_port == 0 && small < 0) {
11727 11712 FP_TRACE(FP_NHEAD1(3, 0),
11728 11713 "fp_i_handle_unsol_els: Mark the pd"
11729 11714 " as plogi recipient, pd=%p, PWWN=%s"
11730 11715 ", sent=%x",
11731 11716 pd, dww_name, sent);
11732 11717 }
11733 11718 } else {
11734 11719 sent = 0;
11735 11720 }
11736 11721
11737 11722 /*
11738 11723 * To avoid Login collisions, accept only if my WWN
11739 11724 * is smaller than the requester (A curious side note
11740 11725 * would be that this rule may not satisfy the PLOGIs
11741 11726 * initiated by the switch from not-so-well known
11742 11727 * ports such as 0xFFFC41)
11743 11728 */
11744 11729 if ((f_port == 0 && small < 0) ||
11745 11730 (((small > 0 && do_acc) ||
11746 11731 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11747 11732 if (fp_is_class_supported(port->fp_cos,
11748 11733 buf->ub_class) == FC_FAILURE) {
11749 11734 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11750 11735 cmd->cmd_pkt.pkt_cmdlen =
11751 11736 sizeof (la_els_rjt_t);
11752 11737 cmd->cmd_pkt.pkt_rsplen = 0;
11753 11738 fp_els_rjt_init(port, cmd, buf,
11754 11739 FC_ACTION_NON_RETRYABLE,
11755 11740 FC_REASON_CLASS_NOT_SUPP, NULL);
11756 11741 FP_TRACE(FP_NHEAD1(3, 0),
11757 11742 "fp_i_handle_unsol_els: "
11758 11743 "Unsupported class. "
11759 11744 "Rejecting PLOGI");
11760 11745
11761 11746 } else {
11762 11747 mutex_enter(&port->fp_mutex);
11763 11748 port->fp_els_resp_pkt_busy = 0;
11764 11749 mutex_exit(&port->fp_mutex);
11765 11750 return;
11766 11751 }
11767 11752 } else {
11768 11753 cmd->cmd_pkt.pkt_cmdlen =
11769 11754 sizeof (la_els_logi_t);
11770 11755 cmd->cmd_pkt.pkt_rsplen = 0;
11771 11756
11772 11757 /*
11773 11758 * If fp_port_id is zero and topology is
11774 11759 * Point-to-Point, get the local port id from
11775 11760 * the d_id in the PLOGI request.
11776 11761 * If the outgoing FLOGI hasn't been accepted,
11777 11762 * the topology will be unknown here. But it's
11778 11763 * still safe to save the d_id to fp_port_id,
11779 11764 * just because it will be overwritten later
11780 11765 * if the topology is not Point-to-Point.
11781 11766 */
11782 11767 mutex_enter(&port->fp_mutex);
11783 11768 if ((port->fp_port_id.port_id == 0) &&
11784 11769 (port->fp_topology == FC_TOP_PT_PT ||
11785 11770 port->fp_topology == FC_TOP_UNKNOWN)) {
11786 11771 port->fp_port_id.port_id =
11787 11772 buf->ub_frame.d_id;
11788 11773 }
11789 11774 mutex_exit(&port->fp_mutex);
11790 11775
11791 11776 /*
11792 11777 * Sometime later, we should validate
11793 11778 * the service parameters instead of
11794 11779 * just accepting it.
11795 11780 */
11796 11781 fp_login_acc_init(port, cmd, buf, NULL,
11797 11782 KM_NOSLEEP);
11798 11783 FP_TRACE(FP_NHEAD1(3, 0),
11799 11784 "fp_i_handle_unsol_els: Accepting PLOGI,"
11800 11785 " f_port=%d, small=%d, do_acc=%d,"
11801 11786 " sent=%d.", f_port, small, do_acc,
11802 11787 sent);
11803 11788 }
11804 11789 } else {
11805 11790 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11806 11791 port->fp_options & FP_SEND_RJT) {
11807 11792 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11808 11793 cmd->cmd_pkt.pkt_rsplen = 0;
11809 11794 fp_els_rjt_init(port, cmd, buf,
11810 11795 FC_ACTION_NON_RETRYABLE,
11811 11796 FC_REASON_LOGICAL_BSY, NULL);
11812 11797 FP_TRACE(FP_NHEAD1(3, 0),
11813 11798 "fp_i_handle_unsol_els: "
11814 11799 "Rejecting PLOGI with Logical Busy."
11815 11800 "Possible Login collision.");
11816 11801 } else {
11817 11802 mutex_enter(&port->fp_mutex);
11818 11803 port->fp_els_resp_pkt_busy = 0;
11819 11804 mutex_exit(&port->fp_mutex);
11820 11805 return;
11821 11806 }
11822 11807 }
11823 11808 break;
11824 11809 }
11825 11810
11826 11811 case LA_ELS_FLOGI:
11827 11812 if (fp_is_class_supported(port->fp_cos,
11828 11813 buf->ub_class) == FC_FAILURE) {
11829 11814 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11830 11815 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11831 11816 cmd->cmd_pkt.pkt_rsplen = 0;
11832 11817 fp_els_rjt_init(port, cmd, buf,
11833 11818 FC_ACTION_NON_RETRYABLE,
11834 11819 FC_REASON_CLASS_NOT_SUPP, NULL);
11835 11820 FP_TRACE(FP_NHEAD1(3, 0),
11836 11821 "fp_i_handle_unsol_els: "
11837 11822 "Unsupported Class. Rejecting FLOGI.");
11838 11823 } else {
11839 11824 mutex_enter(&port->fp_mutex);
11840 11825 port->fp_els_resp_pkt_busy = 0;
11841 11826 mutex_exit(&port->fp_mutex);
11842 11827 return;
11843 11828 }
11844 11829 } else {
11845 11830 mutex_enter(&port->fp_mutex);
11846 11831 if (FC_PORT_STATE_MASK(port->fp_state) !=
11847 11832 FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11848 11833 buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11849 11834 mutex_exit(&port->fp_mutex);
11850 11835 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11851 11836 cmd->cmd_pkt.pkt_cmdlen =
11852 11837 sizeof (la_els_rjt_t);
11853 11838 cmd->cmd_pkt.pkt_rsplen = 0;
11854 11839 fp_els_rjt_init(port, cmd, buf,
11855 11840 FC_ACTION_NON_RETRYABLE,
11856 11841 FC_REASON_INVALID_LINK_CTRL,
11857 11842 NULL);
11858 11843 FP_TRACE(FP_NHEAD1(3, 0),
11859 11844 "fp_i_handle_unsol_els: "
11860 11845 "Invalid Link Ctrl. "
11861 11846 "Rejecting FLOGI.");
11862 11847 } else {
11863 11848 mutex_enter(&port->fp_mutex);
11864 11849 port->fp_els_resp_pkt_busy = 0;
11865 11850 mutex_exit(&port->fp_mutex);
11866 11851 return;
11867 11852 }
11868 11853 } else {
11869 11854 mutex_exit(&port->fp_mutex);
11870 11855 cmd->cmd_pkt.pkt_cmdlen =
11871 11856 sizeof (la_els_logi_t);
11872 11857 cmd->cmd_pkt.pkt_rsplen = 0;
11873 11858 /*
11874 11859 * Let's not aggressively validate the N_Port's
11875 11860 * service parameters until PLOGI. Suffice it
11876 11861 * to give a hint that we are an N_Port and we
11877 11862 * are game to some serious stuff here.
11878 11863 */
11879 11864 fp_login_acc_init(port, cmd, buf,
11880 11865 NULL, KM_NOSLEEP);
11881 11866 FP_TRACE(FP_NHEAD1(3, 0),
11882 11867 "fp_i_handle_unsol_els: "
11883 11868 "Accepting FLOGI.");
11884 11869 }
11885 11870 }
11886 11871 break;
11887 11872
11888 11873 default:
11889 11874 return;
11890 11875 }
11891 11876
11892 11877 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11893 11878 mutex_enter(&port->fp_mutex);
11894 11879 port->fp_els_resp_pkt_busy = 0;
11895 11880 mutex_exit(&port->fp_mutex);
11896 11881 }
11897 11882 }
11898 11883
11899 11884
11900 11885 /*
11901 11886 * Handle unsolicited PLOGI request
11902 11887 */
11903 11888 static void
11904 11889 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11905 11890 job_request_t *job, int sleep)
11906 11891 {
11907 11892 int sent;
11908 11893 int small;
11909 11894 int f_port;
11910 11895 int do_acc;
11911 11896 fp_cmd_t *cmd;
11912 11897 la_wwn_t *swwn;
11913 11898 la_wwn_t *dwwn;
11914 11899 la_els_logi_t *payload;
11915 11900 fc_remote_port_t *pd;
11916 11901 char dww_name[17];
11917 11902
11918 11903 payload = (la_els_logi_t *)buf->ub_buffer;
11919 11904 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11920 11905
11921 11906 mutex_enter(&port->fp_mutex);
11922 11907 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11923 11908 mutex_exit(&port->fp_mutex);
11924 11909
11925 11910 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11926 11911 "type=%x, f_ctl=%x"
11927 11912 " seq_id=%x, ox_id=%x, rx_id=%x"
11928 11913 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11929 11914 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11930 11915 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11931 11916
11932 11917 swwn = &port->fp_service_params.nport_ww_name;
11933 11918 dwwn = &payload->nport_ww_name;
11934 11919 small = fctl_wwn_cmp(swwn, dwwn);
11935 11920 pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11936 11921 if (pd) {
11937 11922 mutex_enter(&pd->pd_mutex);
11938 11923 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11939 11924 /*
11940 11925 * Most likely this means a cross login is in
11941 11926 * progress or a device about to be yanked out.
11942 11927 * Only accept the plogi if my wwn is smaller.
11943 11928 */
11944 11929
11945 11930 if (pd->pd_type == PORT_DEVICE_OLD) {
11946 11931 sent = 1;
11947 11932 }
11948 11933 /*
11949 11934 * Stop plogi request (if any)
11950 11935 * attempt from local side to speedup
11951 11936 * the discovery progress.
11952 11937 * Mark the pd as PD_PLOGI_RECEPIENT.
11953 11938 */
11954 11939 if (f_port == 0 && small < 0) {
11955 11940 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11956 11941 }
11957 11942 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11958 11943
11959 11944 mutex_exit(&pd->pd_mutex);
11960 11945
11961 11946 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11962 11947 " received. PD still exists in the PWWN list. pd=%p "
11963 11948 "PWWN=%s, sent=%x", pd, dww_name, sent);
11964 11949
11965 11950 if (f_port == 0 && small < 0) {
11966 11951 FP_TRACE(FP_NHEAD1(3, 0),
11967 11952 "fp_handle_unsol_plogi: Mark the pd"
11968 11953 " as plogi recipient, pd=%p, PWWN=%s"
11969 11954 ", sent=%x",
11970 11955 pd, dww_name, sent);
11971 11956 }
11972 11957 } else {
11973 11958 sent = 0;
11974 11959 }
11975 11960
11976 11961 /*
11977 11962 * Avoid Login collisions by accepting only if my WWN is smaller.
11978 11963 *
11979 11964 * A side note: There is no need to start a PLOGI from this end in
11980 11965 * this context if login isn't going to be accepted for the
11981 11966 * above reason as either a LIP (in private loop), RSCN (in
11982 11967 * fabric topology), or an FLOGI (in point to point - Huh ?
11983 11968 * check FC-PH) would normally drive the PLOGI from this end.
11984 11969 * At this point of time there is no need for an inbound PLOGI
11985 11970 * to kick an outbound PLOGI when it is going to be rejected
11986 11971 * for the reason of WWN being smaller. However it isn't hard
11987 11972 * to do that either (when such a need arises, start a timer
11988 11973 * for a duration that extends beyond a normal device discovery
11989 11974 * time and check if an outbound PLOGI did go before that, if
11990 11975 * none fire one)
11991 11976 *
11992 11977 * Unfortunately, as it turned out, during booting, it is possible
11993 11978 * to miss another initiator in the same loop as port driver
11994 11979 * instances are serially attached. While preserving the above
11995 11980 * comments for belly laughs, please kick an outbound PLOGI in
11996 11981 * a non-switch environment (which is a pt pt between N_Ports or
11997 11982 * a private loop)
11998 11983 *
11999 11984 * While preserving the above comments for amusement, send an
12000 11985 * ACC if the PLOGI is going to be rejected for WWN being smaller
12001 11986 * when no discovery is in progress at this end. Turn around
12002 11987 * and make the port device as the PLOGI initiator, so that
12003 11988 * during subsequent link/loop initialization, this end drives
12004 11989 * the PLOGI (In fact both ends do in this particular case, but
12005 11990 * only one wins)
12006 11991 *
12007 11992 * Make sure the PLOGIs initiated by the switch from not-so-well-known
12008 11993 * ports (such as 0xFFFC41) are accepted too.
12009 11994 */
12010 11995 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
12011 11996 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
12012 11997 if (fp_is_class_supported(port->fp_cos,
12013 11998 buf->ub_class) == FC_FAILURE) {
12014 11999 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12015 12000 cmd = fp_alloc_pkt(port,
12016 12001 sizeof (la_els_logi_t), 0, sleep, pd);
12017 12002 if (cmd == NULL) {
12018 12003 return;
12019 12004 }
12020 12005 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12021 12006 cmd->cmd_pkt.pkt_rsplen = 0;
12022 12007 fp_els_rjt_init(port, cmd, buf,
12023 12008 FC_ACTION_NON_RETRYABLE,
12024 12009 FC_REASON_CLASS_NOT_SUPP, job);
12025 12010 FP_TRACE(FP_NHEAD1(3, 0),
12026 12011 "fp_handle_unsol_plogi: "
12027 12012 "Unsupported class. rejecting PLOGI");
12028 12013 }
12029 12014 } else {
12030 12015 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12031 12016 0, sleep, pd);
12032 12017 if (cmd == NULL) {
12033 12018 return;
12034 12019 }
12035 12020 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
12036 12021 cmd->cmd_pkt.pkt_rsplen = 0;
12037 12022
12038 12023 /*
12039 12024 * Sometime later, we should validate the service
12040 12025 * parameters instead of just accepting it.
12041 12026 */
12042 12027 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12043 12028 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12044 12029 "Accepting PLOGI, f_port=%d, small=%d, "
12045 12030 "do_acc=%d, sent=%d.", f_port, small, do_acc,
12046 12031 sent);
12047 12032
12048 12033 /*
12049 12034 * If fp_port_id is zero and topology is
12050 12035 * Point-to-Point, get the local port id from
12051 12036 * the d_id in the PLOGI request.
12052 12037 * If the outgoing FLOGI hasn't been accepted,
12053 12038 * the topology will be unknown here. But it's
12054 12039 * still safe to save the d_id to fp_port_id,
12055 12040 * just because it will be overwritten later
12056 12041 * if the topology is not Point-to-Point.
12057 12042 */
12058 12043 mutex_enter(&port->fp_mutex);
12059 12044 if ((port->fp_port_id.port_id == 0) &&
12060 12045 (port->fp_topology == FC_TOP_PT_PT ||
12061 12046 port->fp_topology == FC_TOP_UNKNOWN)) {
12062 12047 port->fp_port_id.port_id =
12063 12048 buf->ub_frame.d_id;
12064 12049 }
12065 12050 mutex_exit(&port->fp_mutex);
12066 12051 }
12067 12052 } else {
12068 12053 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12069 12054 port->fp_options & FP_SEND_RJT) {
12070 12055 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12071 12056 0, sleep, pd);
12072 12057 if (cmd == NULL) {
12073 12058 return;
12074 12059 }
12075 12060 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12076 12061 cmd->cmd_pkt.pkt_rsplen = 0;
12077 12062 /*
12078 12063 * Send out Logical busy to indicate
12079 12064 * the detection of PLOGI collision
12080 12065 */
12081 12066 fp_els_rjt_init(port, cmd, buf,
12082 12067 FC_ACTION_NON_RETRYABLE,
12083 12068 FC_REASON_LOGICAL_BSY, job);
12084 12069
12085 12070 fc_wwn_to_str(dwwn, dww_name);
12086 12071 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12087 12072 "Rejecting Unsol PLOGI with Logical Busy."
12088 12073 "possible PLOGI collision. PWWN=%s, sent=%x",
12089 12074 dww_name, sent);
12090 12075 } else {
12091 12076 return;
12092 12077 }
12093 12078 }
12094 12079
12095 12080 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12096 12081 fp_free_pkt(cmd);
12097 12082 }
12098 12083 }
12099 12084
12100 12085
12101 12086 /*
12102 12087 * Handle mischievous turning over of our own FLOGI requests back to
12103 12088 * us by the SOC+ microcode. In other words, look at the class of such
12104 12089 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12105 12090 * on the floor
12106 12091 */
12107 12092 static void
12108 12093 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12109 12094 job_request_t *job, int sleep)
12110 12095 {
12111 12096 uint32_t state;
12112 12097 uint32_t s_id;
12113 12098 fp_cmd_t *cmd;
12114 12099
12115 12100 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12116 12101 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12117 12102 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12118 12103 0, sleep, NULL);
12119 12104 if (cmd == NULL) {
12120 12105 return;
12121 12106 }
12122 12107 fp_els_rjt_init(port, cmd, buf,
12123 12108 FC_ACTION_NON_RETRYABLE,
12124 12109 FC_REASON_CLASS_NOT_SUPP, job);
12125 12110 } else {
12126 12111 return;
12127 12112 }
12128 12113 } else {
12129 12114
12130 12115 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12131 12116 " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12132 12117 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12133 12118 buf->ub_frame.s_id, buf->ub_frame.d_id,
12134 12119 buf->ub_frame.type, buf->ub_frame.f_ctl,
12135 12120 buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12136 12121 buf->ub_frame.rx_id, buf->ub_frame.ro);
12137 12122
12138 12123 mutex_enter(&port->fp_mutex);
12139 12124 state = FC_PORT_STATE_MASK(port->fp_state);
12140 12125 s_id = port->fp_port_id.port_id;
12141 12126 mutex_exit(&port->fp_mutex);
12142 12127
12143 12128 if (state != FC_STATE_ONLINE ||
12144 12129 (s_id && buf->ub_frame.s_id == s_id)) {
12145 12130 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12146 12131 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12147 12132 0, sleep, NULL);
12148 12133 if (cmd == NULL) {
12149 12134 return;
12150 12135 }
12151 12136 fp_els_rjt_init(port, cmd, buf,
12152 12137 FC_ACTION_NON_RETRYABLE,
12153 12138 FC_REASON_INVALID_LINK_CTRL, job);
12154 12139 FP_TRACE(FP_NHEAD1(3, 0),
12155 12140 "fp_handle_unsol_flogi: "
12156 12141 "Rejecting PLOGI. Invalid Link CTRL");
12157 12142 } else {
12158 12143 return;
12159 12144 }
12160 12145 } else {
12161 12146 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12162 12147 0, sleep, NULL);
12163 12148 if (cmd == NULL) {
12164 12149 return;
12165 12150 }
12166 12151 /*
12167 12152 * Let's not aggressively validate the N_Port's
12168 12153 * service parameters until PLOGI. Suffice it
12169 12154 * to give a hint that we are an N_Port and we
12170 12155 * are game to some serious stuff here.
12171 12156 */
12172 12157 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12173 12158 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12174 12159 "Accepting PLOGI");
12175 12160 }
12176 12161 }
12177 12162
12178 12163 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12179 12164 fp_free_pkt(cmd);
12180 12165 }
12181 12166 }
12182 12167
12183 12168
12184 12169 /*
12185 12170 * Perform PLOGI accept
12186 12171 */
12187 12172 static void
12188 12173 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12189 12174 job_request_t *job, int sleep)
12190 12175 {
12191 12176 fc_packet_t *pkt;
12192 12177 fc_portmap_t *listptr;
12193 12178 la_els_logi_t payload;
12194 12179
12195 12180 ASSERT(buf != NULL);
12196 12181
12197 12182 /*
12198 12183 * If we are sending ACC to PLOGI and we haven't already
12199 12184 * create port and node device handles, let's create them
12200 12185 * here.
12201 12186 */
12202 12187 if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12203 12188 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12204 12189 int small;
12205 12190 int do_acc;
12206 12191 fc_remote_port_t *pd;
12207 12192 la_els_logi_t *req;
12208 12193
12209 12194 req = (la_els_logi_t *)buf->ub_buffer;
12210 12195 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12211 12196 &req->nport_ww_name);
12212 12197
12213 12198 mutex_enter(&port->fp_mutex);
12214 12199 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12215 12200 mutex_exit(&port->fp_mutex);
12216 12201
12217 12202 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12218 12203 port->fp_port_id.port_id, buf->ub_frame.s_id);
12219 12204 pd = fctl_create_remote_port(port, &req->node_ww_name,
12220 12205 &req->nport_ww_name, buf->ub_frame.s_id,
12221 12206 PD_PLOGI_RECEPIENT, sleep);
12222 12207 if (pd == NULL) {
12223 12208 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12224 12209 "Couldn't create port device for d_id:0x%x",
12225 12210 buf->ub_frame.s_id);
12226 12211
12227 12212 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12228 12213 "couldn't create port device d_id=%x",
12229 12214 buf->ub_frame.s_id);
12230 12215 } else {
12231 12216 /*
12232 12217 * usoc currently returns PLOGIs inline and
12233 12218 * the maximum buffer size is 60 bytes or so.
12234 12219 * So attempt not to look beyond what is in
12235 12220 * the unsolicited buffer
12236 12221 *
12237 12222 * JNI also traverses this path sometimes
12238 12223 */
12239 12224 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12240 12225 fp_register_login(NULL, pd, req, buf->ub_class);
12241 12226 } else {
12242 12227 mutex_enter(&pd->pd_mutex);
12243 12228 if (pd->pd_login_count == 0) {
12244 12229 pd->pd_login_count++;
12245 12230 }
12246 12231 pd->pd_state = PORT_DEVICE_LOGGED_IN;
12247 12232 pd->pd_login_class = buf->ub_class;
12248 12233 mutex_exit(&pd->pd_mutex);
12249 12234 }
12250 12235
12251 12236 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12252 12237 if (listptr != NULL) {
12253 12238 fctl_copy_portmap(listptr, pd);
12254 12239 (void) fp_ulp_devc_cb(port, listptr,
12255 12240 1, 1, sleep, 0);
12256 12241 }
12257 12242
12258 12243 if (small > 0 && do_acc) {
12259 12244 mutex_enter(&pd->pd_mutex);
12260 12245 pd->pd_recepient = PD_PLOGI_INITIATOR;
12261 12246 mutex_exit(&pd->pd_mutex);
12262 12247 }
12263 12248 }
12264 12249 }
12265 12250
12266 12251 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12267 12252 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12268 12253 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12269 12254 cmd->cmd_retry_count = 1;
12270 12255 cmd->cmd_ulp_pkt = NULL;
12271 12256
12272 12257 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12273 12258 cmd->cmd_job = job;
12274 12259
12275 12260 pkt = &cmd->cmd_pkt;
12276 12261
12277 12262 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12278 12263
12279 12264 payload = port->fp_service_params;
12280 12265 payload.ls_code.ls_code = LA_ELS_ACC;
12281 12266
12282 12267 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12283 12268 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12284 12269
12285 12270 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12286 12271 "bufsize:0x%x sizeof (la_els_logi):0x%x "
12287 12272 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12288 12273 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12289 12274 buf->ub_bufsize, sizeof (la_els_logi_t),
12290 12275 port->fp_service_params.nport_ww_name.w.naa_id,
12291 12276 port->fp_service_params.nport_ww_name.w.nport_id,
12292 12277 port->fp_service_params.nport_ww_name.w.wwn_hi,
12293 12278 port->fp_service_params.nport_ww_name.w.wwn_lo,
12294 12279 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12295 12280 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12296 12281 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12297 12282 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12298 12283 port->fp_statec_busy);
12299 12284 }
12300 12285
12301 12286
12302 12287 #define RSCN_EVENT_NAME_LEN 256
12303 12288
12304 12289 /*
12305 12290 * Handle RSCNs
12306 12291 */
12307 12292 static void
12308 12293 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12309 12294 job_request_t *job, int sleep)
12310 12295 {
12311 12296 uint32_t mask;
12312 12297 fp_cmd_t *cmd;
12313 12298 uint32_t count;
12314 12299 int listindex;
12315 12300 int16_t len;
12316 12301 fc_rscn_t *payload;
12317 12302 fc_portmap_t *listptr;
12318 12303 fctl_ns_req_t *ns_cmd;
12319 12304 fc_affected_id_t *page;
12320 12305 caddr_t nvname;
12321 12306 nvlist_t *attr_list = NULL;
12322 12307
12323 12308 mutex_enter(&port->fp_mutex);
12324 12309 if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12325 12310 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12326 12311 --port->fp_rscn_count;
12327 12312 }
12328 12313 mutex_exit(&port->fp_mutex);
12329 12314 return;
12330 12315 }
12331 12316 mutex_exit(&port->fp_mutex);
12332 12317
12333 12318 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12334 12319 if (cmd != NULL) {
12335 12320 fp_els_acc_init(port, cmd, buf, job);
12336 12321 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12337 12322 fp_free_pkt(cmd);
12338 12323 }
12339 12324 }
12340 12325
12341 12326 payload = (fc_rscn_t *)buf->ub_buffer;
12342 12327 ASSERT(payload->rscn_code == LA_ELS_RSCN);
12343 12328 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12344 12329
12345 12330 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12346 12331
12347 12332 if (len <= 0) {
12348 12333 mutex_enter(&port->fp_mutex);
12349 12334 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12350 12335 --port->fp_rscn_count;
12351 12336 }
12352 12337 mutex_exit(&port->fp_mutex);
12353 12338
12354 12339 return;
12355 12340 }
12356 12341
12357 12342 ASSERT((len & 0x3) == 0); /* Must be power of 4 */
12358 12343 count = (len >> 2) << 1; /* number of pages multiplied by 2 */
12359 12344
12360 12345 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12361 12346 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12362 12347
12363 12348 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12364 12349
12365 12350 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12366 12351 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12367 12352 0, sleep);
12368 12353 if (ns_cmd == NULL) {
12369 12354 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12370 12355
12371 12356 mutex_enter(&port->fp_mutex);
12372 12357 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12373 12358 --port->fp_rscn_count;
12374 12359 }
12375 12360 mutex_exit(&port->fp_mutex);
12376 12361
12377 12362 return;
12378 12363 }
12379 12364
12380 12365 ns_cmd->ns_cmd_code = NS_GPN_ID;
12381 12366
12382 12367 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12383 12368 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12384 12369 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12385 12370 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12386 12371 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12387 12372
12388 12373 /* Only proceed if we can allocate nvname and the nvlist */
12389 12374 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12390 12375 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12391 12376 KM_NOSLEEP) == DDI_SUCCESS) {
12392 12377 if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12393 12378 port->fp_instance) == DDI_SUCCESS &&
12394 12379 nvlist_add_byte_array(attr_list, "port-wwn",
12395 12380 port->fp_service_params.nport_ww_name.raw_wwn,
12396 12381 sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12397 12382 nvlist_free(attr_list);
12398 12383 attr_list = NULL;
12399 12384 }
12400 12385 }
12401 12386
12402 12387 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12403 12388 /* Add affected page to the event payload */
12404 12389 if (attr_list != NULL) {
12405 12390 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12406 12391 "affected_page_%d", listindex);
12407 12392 if (attr_list && nvlist_add_uint32(attr_list, nvname,
12408 12393 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12409 12394 /* We don't send a partial event, so dump it */
12410 12395 nvlist_free(attr_list);
12411 12396 attr_list = NULL;
12412 12397 }
12413 12398 }
12414 12399 /*
12415 12400 * Query the NS to get the Port WWN for this
12416 12401 * affected D_ID.
12417 12402 */
12418 12403 mask = 0;
12419 12404 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12420 12405 case FC_RSCN_PORT_ADDRESS:
12421 12406 fp_validate_rscn_page(port, page, job, ns_cmd,
12422 12407 listptr, &listindex, sleep);
12423 12408
12424 12409 if (listindex == 0) {
12425 12410 /*
12426 12411 * We essentially did not process this RSCN. So,
12427 12412 * ULPs are not going to be called and so we
12428 12413 * decrement the rscn_count
12429 12414 */
12430 12415 mutex_enter(&port->fp_mutex);
12431 12416 if (--port->fp_rscn_count ==
12432 12417 FC_INVALID_RSCN_COUNT) {
12433 12418 --port->fp_rscn_count;
12434 12419 }
12435 12420 mutex_exit(&port->fp_mutex);
12436 12421 }
12437 12422 break;
12438 12423
12439 12424 case FC_RSCN_AREA_ADDRESS:
12440 12425 mask = 0xFFFF00;
12441 12426 /* FALLTHROUGH */
12442 12427
12443 12428 case FC_RSCN_DOMAIN_ADDRESS:
12444 12429 if (!mask) {
12445 12430 mask = 0xFF0000;
12446 12431 }
12447 12432 fp_validate_area_domain(port, page->aff_d_id, mask,
12448 12433 job, sleep);
12449 12434 break;
12450 12435
12451 12436 case FC_RSCN_FABRIC_ADDRESS:
12452 12437 /*
12453 12438 * We need to discover all the devices on this
12454 12439 * port.
12455 12440 */
12456 12441 fp_validate_area_domain(port, 0, 0, job, sleep);
12457 12442 break;
12458 12443
12459 12444 default:
12460 12445 break;
12461 12446 }
12462 12447 }
12463 12448 if (attr_list != NULL) {
12464 12449 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12465 12450 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12466 12451 NULL, DDI_SLEEP);
12467 12452 nvlist_free(attr_list);
12468 12453 } else {
12469 12454 FP_TRACE(FP_NHEAD1(9, 0),
12470 12455 "RSCN handled, but event not sent to userland");
12471 12456 }
12472 12457 if (nvname != NULL) {
12473 12458 kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12474 12459 }
12475 12460
12476 12461 if (ns_cmd) {
12477 12462 fctl_free_ns_cmd(ns_cmd);
12478 12463 }
12479 12464
12480 12465 if (listindex) {
12481 12466 #ifdef DEBUG
12482 12467 page = (fc_affected_id_t *)(buf->ub_buffer +
12483 12468 sizeof (fc_rscn_t));
12484 12469
12485 12470 if (listptr->map_did.port_id != page->aff_d_id) {
12486 12471 FP_TRACE(FP_NHEAD1(9, 0),
12487 12472 "PORT RSCN: processed=%x, reporting=%x",
12488 12473 listptr->map_did.port_id, page->aff_d_id);
12489 12474 }
12490 12475 #endif
12491 12476
12492 12477 (void) fp_ulp_devc_cb(port, listptr, listindex, count,
12493 12478 sleep, 0);
12494 12479 } else {
12495 12480 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12496 12481 }
12497 12482 }
12498 12483
12499 12484
12500 12485 /*
12501 12486 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12502 12487 */
12503 12488 static void
12504 12489 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12505 12490 {
12506 12491 int is_switch;
12507 12492 int initiator;
12508 12493 fc_local_port_t *port;
12509 12494
12510 12495 port = pd->pd_port;
12511 12496
12512 12497 /* This function has the following bunch of assumptions */
12513 12498 ASSERT(port != NULL);
12514 12499 ASSERT(MUTEX_HELD(&port->fp_mutex));
12515 12500 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12516 12501 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12517 12502
12518 12503 pd->pd_state = PORT_DEVICE_INVALID;
12519 12504 pd->pd_type = PORT_DEVICE_OLD;
12520 12505 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12521 12506 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12522 12507
12523 12508 fctl_delist_did_table(port, pd);
12524 12509 fctl_delist_pwwn_table(port, pd);
12525 12510
12526 12511 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12527 12512 " removed the PD=%p from DID and PWWN tables",
12528 12513 port, pd->pd_port_id.port_id, pd);
12529 12514
12530 12515 if ((!flag) && port && initiator && is_switch) {
12531 12516 (void) fctl_add_orphan_held(port, pd);
12532 12517 }
12533 12518 fctl_copy_portmap_held(map, pd);
12534 12519 map->map_pd = pd;
12535 12520 }
12536 12521
12537 12522 /*
12538 12523 * Fill out old map for ULPs
12539 12524 */
12540 12525 static void
12541 12526 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12542 12527 {
12543 12528 int is_switch;
12544 12529 int initiator;
12545 12530 fc_local_port_t *port;
12546 12531
12547 12532 mutex_enter(&pd->pd_mutex);
12548 12533 port = pd->pd_port;
12549 12534 mutex_exit(&pd->pd_mutex);
12550 12535
12551 12536 mutex_enter(&port->fp_mutex);
12552 12537 mutex_enter(&pd->pd_mutex);
12553 12538
12554 12539 pd->pd_state = PORT_DEVICE_INVALID;
12555 12540 pd->pd_type = PORT_DEVICE_OLD;
12556 12541 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12557 12542 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12558 12543
12559 12544 fctl_delist_did_table(port, pd);
12560 12545 fctl_delist_pwwn_table(port, pd);
12561 12546
12562 12547 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12563 12548 " removed the PD=%p from DID and PWWN tables",
12564 12549 port, pd->pd_port_id.port_id, pd);
12565 12550
12566 12551 mutex_exit(&pd->pd_mutex);
12567 12552 mutex_exit(&port->fp_mutex);
12568 12553
12569 12554 ASSERT(port != NULL);
12570 12555 if ((!flag) && port && initiator && is_switch) {
12571 12556 (void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12572 12557 }
12573 12558 fctl_copy_portmap(map, pd);
12574 12559 map->map_pd = pd;
12575 12560 }
12576 12561
12577 12562
12578 12563 /*
12579 12564 * Fillout Changed Map for ULPs
12580 12565 */
12581 12566 static void
12582 12567 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12583 12568 uint32_t *new_did, la_wwn_t *new_pwwn)
12584 12569 {
12585 12570 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12586 12571
12587 12572 pd->pd_type = PORT_DEVICE_CHANGED;
12588 12573 if (new_did) {
12589 12574 pd->pd_port_id.port_id = *new_did;
12590 12575 }
12591 12576 if (new_pwwn) {
12592 12577 pd->pd_port_name = *new_pwwn;
12593 12578 }
12594 12579 mutex_exit(&pd->pd_mutex);
12595 12580
12596 12581 fctl_copy_portmap(map, pd);
12597 12582
12598 12583 mutex_enter(&pd->pd_mutex);
12599 12584 pd->pd_type = PORT_DEVICE_NOCHANGE;
12600 12585 }
12601 12586
12602 12587
12603 12588 /*
12604 12589 * Fillout New Name Server map
12605 12590 */
12606 12591 static void
12607 12592 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12608 12593 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12609 12594 {
12610 12595 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12611 12596
12612 12597 if (handle) {
12613 12598 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12614 12599 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12615 12600 DDI_DEV_AUTOINCR);
12616 12601 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12617 12602 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12618 12603 DDI_DEV_AUTOINCR);
12619 12604 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12620 12605 (uint8_t *)gan_resp->gan_fc4types,
12621 12606 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12622 12607 } else {
12623 12608 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12624 12609 sizeof (gan_resp->gan_pwwn));
12625 12610 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12626 12611 sizeof (gan_resp->gan_nwwn));
12627 12612 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12628 12613 sizeof (gan_resp->gan_fc4types));
12629 12614 }
12630 12615 port_map->map_did.port_id = d_id;
12631 12616 port_map->map_did.priv_lilp_posit = 0;
12632 12617 port_map->map_hard_addr.hard_addr = 0;
12633 12618 port_map->map_hard_addr.rsvd = 0;
12634 12619 port_map->map_state = PORT_DEVICE_INVALID;
12635 12620 port_map->map_type = PORT_DEVICE_NEW;
12636 12621 port_map->map_flags = 0;
12637 12622 port_map->map_pd = NULL;
12638 12623
12639 12624 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12640 12625
12641 12626 ASSERT(port != NULL);
12642 12627 }
12643 12628
12644 12629
12645 12630 /*
12646 12631 * Perform LINIT ELS
12647 12632 */
12648 12633 static int
12649 12634 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12650 12635 job_request_t *job)
12651 12636 {
12652 12637 int rval;
12653 12638 uint32_t d_id;
12654 12639 uint32_t s_id;
12655 12640 uint32_t lfa;
12656 12641 uchar_t class;
12657 12642 uint32_t ret;
12658 12643 fp_cmd_t *cmd;
12659 12644 fc_porttype_t ptype;
12660 12645 fc_packet_t *pkt;
12661 12646 fc_linit_req_t payload;
12662 12647 fc_remote_port_t *pd;
12663 12648
12664 12649 rval = 0;
12665 12650
12666 12651 ASSERT(job != NULL);
12667 12652 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12668 12653
12669 12654 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12670 12655 if (pd == NULL) {
12671 12656 fctl_ns_req_t *ns_cmd;
12672 12657
12673 12658 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12674 12659 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12675 12660 0, sleep);
12676 12661
12677 12662 if (ns_cmd == NULL) {
12678 12663 return (FC_NOMEM);
12679 12664 }
12680 12665 job->job_result = FC_SUCCESS;
12681 12666 ns_cmd->ns_cmd_code = NS_GID_PN;
12682 12667 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12683 12668
12684 12669 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12685 12670 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12686 12671 fctl_free_ns_cmd(ns_cmd);
12687 12672 return (FC_FAILURE);
12688 12673 }
12689 12674 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12690 12675 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12691 12676
12692 12677 fctl_free_ns_cmd(ns_cmd);
12693 12678 lfa = d_id & 0xFFFF00;
12694 12679
12695 12680 /*
12696 12681 * Given this D_ID, get the port type to see if
12697 12682 * we can do LINIT on the LFA
12698 12683 */
12699 12684 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12700 12685 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12701 12686 0, sleep);
12702 12687
12703 12688 if (ns_cmd == NULL) {
12704 12689 return (FC_NOMEM);
12705 12690 }
12706 12691
12707 12692 job->job_result = FC_SUCCESS;
12708 12693 ns_cmd->ns_cmd_code = NS_GPT_ID;
12709 12694
12710 12695 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12711 12696 ((ns_req_gpt_id_t *)
12712 12697 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12713 12698
12714 12699 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12715 12700 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12716 12701 fctl_free_ns_cmd(ns_cmd);
12717 12702 return (FC_FAILURE);
12718 12703 }
12719 12704 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12720 12705
12721 12706 fctl_free_ns_cmd(ns_cmd);
12722 12707
12723 12708 switch (ptype.port_type) {
12724 12709 case FC_NS_PORT_NL:
12725 12710 case FC_NS_PORT_F_NL:
12726 12711 case FC_NS_PORT_FL:
12727 12712 break;
12728 12713
12729 12714 default:
12730 12715 return (FC_FAILURE);
12731 12716 }
12732 12717 } else {
12733 12718 mutex_enter(&pd->pd_mutex);
12734 12719 ptype = pd->pd_porttype;
12735 12720
12736 12721 switch (pd->pd_porttype.port_type) {
12737 12722 case FC_NS_PORT_NL:
12738 12723 case FC_NS_PORT_F_NL:
12739 12724 case FC_NS_PORT_FL:
12740 12725 lfa = pd->pd_port_id.port_id & 0xFFFF00;
12741 12726 break;
12742 12727
12743 12728 default:
12744 12729 mutex_exit(&pd->pd_mutex);
12745 12730 return (FC_FAILURE);
12746 12731 }
12747 12732 mutex_exit(&pd->pd_mutex);
12748 12733 }
12749 12734
12750 12735 mutex_enter(&port->fp_mutex);
12751 12736 s_id = port->fp_port_id.port_id;
12752 12737 class = port->fp_ns_login_class;
12753 12738 mutex_exit(&port->fp_mutex);
12754 12739
12755 12740 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12756 12741 sizeof (fc_linit_resp_t), sleep, pd);
12757 12742 if (cmd == NULL) {
12758 12743 return (FC_NOMEM);
12759 12744 }
12760 12745
12761 12746 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12762 12747 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12763 12748 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12764 12749 cmd->cmd_retry_count = fp_retry_count;
12765 12750 cmd->cmd_ulp_pkt = NULL;
12766 12751
12767 12752 pkt = &cmd->cmd_pkt;
12768 12753 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12769 12754
12770 12755 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12771 12756
12772 12757 /*
12773 12758 * How does LIP work by the way ?
12774 12759 * If the L_Port receives three consecutive identical ordered
12775 12760 * sets whose first two characters (fully decoded) are equal to
12776 12761 * the values shown in Table 3 of FC-AL-2 then the L_Port shall
12777 12762 * recognize a Loop Initialization Primitive sequence. The
12778 12763 * character 3 determines the type of lip:
12779 12764 * LIP(F7) Normal LIP
12780 12765 * LIP(F8) Loop Failure LIP
12781 12766 *
12782 12767 * The possible combination for the 3rd and 4th bytes are:
12783 12768 * F7, F7 Normal Lip - No valid AL_PA
12784 12769 * F8, F8 Loop Failure - No valid AL_PA
12785 12770 * F7, AL_PS Normal Lip - Valid source AL_PA
12786 12771 * F8, AL_PS Loop Failure - Valid source AL_PA
12787 12772 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS
12788 12773 * And Normal Lip for all other loop members
12789 12774 * 0xFF AL_PS Vendor specific reset of all loop members
12790 12775 *
12791 12776 * Now, it may not always be that we, at the source, may have an
12792 12777 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12793 12778 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12794 12779 * payload we are going to set:
12795 12780 * lip_b3 = 0xF7; Normal LIP
12796 12781 * lip_b4 = 0xF7; No valid source AL_PA
12797 12782 */
12798 12783 payload.ls_code.ls_code = LA_ELS_LINIT;
12799 12784 payload.ls_code.mbz = 0;
12800 12785 payload.rsvd = 0;
12801 12786 payload.func = 0; /* Let Fabric determine the best way */
12802 12787 payload.lip_b3 = 0xF7; /* Normal LIP */
12803 12788 payload.lip_b4 = 0xF7; /* No valid source AL_PA */
12804 12789
12805 12790 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12806 12791 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12807 12792
12808 12793 job->job_counter = 1;
12809 12794
12810 12795 ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12811 12796 if (ret == FC_SUCCESS) {
12812 12797 fp_jobwait(job);
12813 12798 rval = job->job_result;
12814 12799 } else {
12815 12800 rval = FC_FAILURE;
12816 12801 fp_free_pkt(cmd);
12817 12802 }
12818 12803
12819 12804 return (rval);
12820 12805 }
12821 12806
12822 12807
12823 12808 /*
12824 12809 * Fill out the device handles with GAN response
12825 12810 */
12826 12811 static void
12827 12812 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12828 12813 ns_resp_gan_t *gan_resp)
12829 12814 {
12830 12815 fc_remote_node_t *node;
12831 12816 fc_porttype_t type;
12832 12817 fc_local_port_t *port;
12833 12818
12834 12819 ASSERT(pd != NULL);
12835 12820 ASSERT(handle != NULL);
12836 12821
12837 12822 port = pd->pd_port;
12838 12823
12839 12824 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12840 12825 " port_id=%x, sym_len=%d fc4-type=%x",
12841 12826 pd, gan_resp->gan_type_id.rsvd,
12842 12827 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12843 12828
12844 12829 mutex_enter(&pd->pd_mutex);
12845 12830
12846 12831 FC_GET_RSP(port, *handle, (uint8_t *)&type,
12847 12832 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12848 12833
12849 12834 pd->pd_porttype.port_type = type.port_type;
12850 12835 pd->pd_porttype.rsvd = 0;
12851 12836
12852 12837 pd->pd_spn_len = gan_resp->gan_spnlen;
12853 12838 if (pd->pd_spn_len) {
12854 12839 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12855 12840 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12856 12841 DDI_DEV_AUTOINCR);
12857 12842 }
12858 12843
12859 12844 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12860 12845 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12861 12846 DDI_DEV_AUTOINCR);
12862 12847 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12863 12848 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12864 12849 DDI_DEV_AUTOINCR);
12865 12850 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12866 12851 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12867 12852 DDI_DEV_AUTOINCR);
12868 12853
12869 12854 node = pd->pd_remote_nodep;
12870 12855 mutex_exit(&pd->pd_mutex);
12871 12856
12872 12857 mutex_enter(&node->fd_mutex);
12873 12858
12874 12859 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12875 12860 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12876 12861 DDI_DEV_AUTOINCR);
12877 12862
12878 12863 node->fd_snn_len = gan_resp->gan_snnlen;
12879 12864 if (node->fd_snn_len) {
12880 12865 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12881 12866 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12882 12867 DDI_DEV_AUTOINCR);
12883 12868 }
12884 12869
12885 12870 mutex_exit(&node->fd_mutex);
12886 12871 }
12887 12872
12888 12873
12889 12874 /*
12890 12875 * Handles all NS Queries (also means that this function
12891 12876 * doesn't handle NS object registration)
12892 12877 */
12893 12878 static int
12894 12879 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12895 12880 int polled, int sleep)
12896 12881 {
12897 12882 int rval;
12898 12883 fp_cmd_t *cmd;
12899 12884
12900 12885 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12901 12886
12902 12887 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12903 12888 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12904 12889 port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12905 12890 }
12906 12891
12907 12892 if (ns_cmd->ns_cmd_size == 0) {
12908 12893 return (FC_FAILURE);
12909 12894 }
12910 12895
12911 12896 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12912 12897 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12913 12898 ns_cmd->ns_resp_size, sleep, NULL);
12914 12899 if (cmd == NULL) {
12915 12900 return (FC_NOMEM);
12916 12901 }
12917 12902
12918 12903 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12919 12904 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12920 12905
12921 12906 if (polled) {
12922 12907 job->job_counter = 1;
12923 12908 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12924 12909 }
12925 12910 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12926 12911 if (rval != FC_SUCCESS) {
12927 12912 job->job_result = rval;
12928 12913 fp_iodone(cmd);
12929 12914 if (polled == 0) {
12930 12915 /*
12931 12916 * Return FC_SUCCESS to indicate that
12932 12917 * fp_iodone is performed already.
12933 12918 */
12934 12919 rval = FC_SUCCESS;
12935 12920 }
12936 12921 }
12937 12922
12938 12923 if (polled) {
12939 12924 fp_jobwait(job);
12940 12925 rval = job->job_result;
12941 12926 }
12942 12927
12943 12928 return (rval);
12944 12929 }
12945 12930
12946 12931
12947 12932 /*
12948 12933 * Initialize Common Transport request
12949 12934 */
12950 12935 static void
12951 12936 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12952 12937 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12953 12938 uint16_t resp_len, job_request_t *job)
12954 12939 {
12955 12940 uint32_t s_id;
12956 12941 uchar_t class;
12957 12942 fc_packet_t *pkt;
12958 12943 fc_ct_header_t ct;
12959 12944
12960 12945 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12961 12946
12962 12947 mutex_enter(&port->fp_mutex);
12963 12948 s_id = port->fp_port_id.port_id;
12964 12949 class = port->fp_ns_login_class;
12965 12950 mutex_exit(&port->fp_mutex);
12966 12951
12967 12952 cmd->cmd_job = job;
12968 12953 cmd->cmd_private = ns_cmd;
12969 12954 pkt = &cmd->cmd_pkt;
12970 12955
12971 12956 ct.ct_rev = CT_REV;
12972 12957 ct.ct_inid = 0;
12973 12958 ct.ct_fcstype = FCSTYPE_DIRECTORY;
12974 12959 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12975 12960 ct.ct_options = 0;
12976 12961 ct.ct_reserved1 = 0;
12977 12962 ct.ct_cmdrsp = cmd_code;
12978 12963 ct.ct_aiusize = resp_len >> 2;
12979 12964 ct.ct_reserved2 = 0;
12980 12965 ct.ct_reason = 0;
12981 12966 ct.ct_expln = 0;
12982 12967 ct.ct_vendor = 0;
12983 12968
12984 12969 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12985 12970 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12986 12971
12987 12972 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12988 12973 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12989 12974 pkt->pkt_cmd_fhdr.s_id = s_id;
12990 12975 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12991 12976 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12992 12977 F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12993 12978 pkt->pkt_cmd_fhdr.seq_id = 0;
12994 12979 pkt->pkt_cmd_fhdr.df_ctl = 0;
12995 12980 pkt->pkt_cmd_fhdr.seq_cnt = 0;
12996 12981 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12997 12982 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12998 12983 pkt->pkt_cmd_fhdr.ro = 0;
12999 12984 pkt->pkt_cmd_fhdr.rsvd = 0;
13000 12985
13001 12986 pkt->pkt_comp = fp_ns_intr;
13002 12987 pkt->pkt_ulp_private = (opaque_t)cmd;
13003 12988 pkt->pkt_timeout = FP_NS_TIMEOUT;
13004 12989
13005 12990 if (cmd_buf) {
13006 12991 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
13007 12992 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13008 12993 cmd_len, DDI_DEV_AUTOINCR);
13009 12994 }
13010 12995
13011 12996 cmd->cmd_transport = port->fp_fca_tran->fca_transport;
13012 12997
13013 12998 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
13014 12999 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13015 13000 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
13016 13001 cmd->cmd_retry_count = fp_retry_count;
13017 13002 cmd->cmd_ulp_pkt = NULL;
13018 13003 }
13019 13004
13020 13005
13021 13006 /*
13022 13007 * Name Server request interrupt routine
13023 13008 */
13024 13009 static void
13025 13010 fp_ns_intr(fc_packet_t *pkt)
13026 13011 {
13027 13012 fp_cmd_t *cmd;
13028 13013 fc_local_port_t *port;
13029 13014 fc_ct_header_t resp_hdr;
13030 13015 fc_ct_header_t cmd_hdr;
13031 13016 fctl_ns_req_t *ns_cmd;
13032 13017
13033 13018 cmd = pkt->pkt_ulp_private;
13034 13019 port = cmd->cmd_port;
13035 13020
13036 13021 mutex_enter(&port->fp_mutex);
13037 13022 port->fp_out_fpcmds--;
13038 13023 mutex_exit(&port->fp_mutex);
13039 13024
13040 13025 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
13041 13026 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
13042 13027 ns_cmd = (fctl_ns_req_t *)
13043 13028 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
13044 13029 if (!FP_IS_PKT_ERROR(pkt)) {
13045 13030 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
13046 13031 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
13047 13032 DDI_DEV_AUTOINCR);
13048 13033
13049 13034 /*
13050 13035 * On x86 architectures, make sure the resp_hdr is big endian.
13051 13036 * This macro is a NOP on sparc architectures mainly because
13052 13037 * we don't want to end up wasting time since the end result
13053 13038 * is going to be the same.
13054 13039 */
13055 13040 MAKE_BE_32(&resp_hdr);
13056 13041
13057 13042 if (ns_cmd) {
13058 13043 /*
13059 13044 * Always copy out the response CT_HDR
13060 13045 */
13061 13046 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
13062 13047 sizeof (resp_hdr));
13063 13048 }
13064 13049
13065 13050 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
13066 13051 pkt->pkt_state = FC_PKT_FS_RJT;
13067 13052 pkt->pkt_reason = resp_hdr.ct_reason;
13068 13053 pkt->pkt_expln = resp_hdr.ct_expln;
13069 13054 }
13070 13055 }
13071 13056
13072 13057 if (FP_IS_PKT_ERROR(pkt)) {
13073 13058 if (ns_cmd) {
13074 13059 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13075 13060 ASSERT(ns_cmd->ns_pd != NULL);
13076 13061
13077 13062 /* Mark it OLD if not already done */
13078 13063 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13079 13064 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13080 13065 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13081 13066 }
13082 13067
13083 13068 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13084 13069 fctl_free_ns_cmd(ns_cmd);
13085 13070 ((fp_cmd_t *)
13086 13071 (pkt->pkt_ulp_private))->cmd_private = NULL;
13087 13072 }
13088 13073
13089 13074 }
13090 13075
13091 13076 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x "
13092 13077 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13093 13078 port->fp_port_id.port_id, pkt->pkt_state,
13094 13079 pkt->pkt_reason, pkt->pkt_expln,
13095 13080 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp);
13096 13081
13097 13082 (void) fp_common_intr(pkt, 1);
13098 13083
13099 13084 return;
13100 13085 }
13101 13086
13102 13087 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13103 13088 uint32_t d_id;
13104 13089 fc_local_port_t *port;
13105 13090 fp_cmd_t *cmd;
13106 13091
13107 13092 d_id = pkt->pkt_cmd_fhdr.d_id;
13108 13093 cmd = pkt->pkt_ulp_private;
13109 13094 port = cmd->cmd_port;
13110 13095 FP_TRACE(FP_NHEAD2(9, 0),
13111 13096 "Bogus NS response received for D_ID=%x", d_id);
13112 13097 }
13113 13098
13114 13099 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13115 13100 fp_gan_handler(pkt, ns_cmd);
13116 13101 return;
13117 13102 }
13118 13103
13119 13104 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13120 13105 cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13121 13106 if (ns_cmd) {
13122 13107 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13123 13108 fp_ns_query_handler(pkt, ns_cmd);
13124 13109 return;
13125 13110 }
13126 13111 }
13127 13112 }
13128 13113
13129 13114 fp_iodone(pkt->pkt_ulp_private);
13130 13115 }
13131 13116
13132 13117
13133 13118 /*
13134 13119 * Process NS_GAN response
13135 13120 */
13136 13121 static void
13137 13122 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13138 13123 {
13139 13124 int my_did;
13140 13125 fc_portid_t d_id;
13141 13126 fp_cmd_t *cmd;
13142 13127 fc_local_port_t *port;
13143 13128 fc_remote_port_t *pd;
13144 13129 ns_req_gan_t gan_req;
13145 13130 ns_resp_gan_t *gan_resp;
13146 13131
13147 13132 ASSERT(ns_cmd != NULL);
13148 13133
13149 13134 cmd = pkt->pkt_ulp_private;
13150 13135 port = cmd->cmd_port;
13151 13136
13152 13137 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13153 13138
13154 13139 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13155 13140 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13156 13141
13157 13142 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13158 13143
13159 13144 /*
13160 13145 * In this case the priv_lilp_posit field in reality
13161 13146 * is actually represents the relative position on a private loop.
13162 13147 * So zero it while dealing with Port Identifiers.
13163 13148 */
13164 13149 d_id.priv_lilp_posit = 0;
13165 13150 pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13166 13151 if (ns_cmd->ns_gan_sid == d_id.port_id) {
13167 13152 /*
13168 13153 * We've come a full circle; time to get out.
13169 13154 */
13170 13155 fp_iodone(cmd);
13171 13156 return;
13172 13157 }
13173 13158
13174 13159 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13175 13160 ns_cmd->ns_gan_sid = d_id.port_id;
13176 13161 }
13177 13162
13178 13163 mutex_enter(&port->fp_mutex);
13179 13164 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13180 13165 mutex_exit(&port->fp_mutex);
13181 13166
13182 13167 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13183 13168 port->fp_port_id.port_id, d_id.port_id);
13184 13169 if (my_did == 0) {
13185 13170 la_wwn_t pwwn;
13186 13171 la_wwn_t nwwn;
13187 13172
13188 13173 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13189 13174 "port=%p, d_id=%x, type_id=%x, "
13190 13175 "pwwn=%x %x %x %x %x %x %x %x, "
13191 13176 "nwwn=%x %x %x %x %x %x %x %x",
13192 13177 port, d_id.port_id, gan_resp->gan_type_id,
13193 13178
13194 13179 gan_resp->gan_pwwn.raw_wwn[0],
13195 13180 gan_resp->gan_pwwn.raw_wwn[1],
13196 13181 gan_resp->gan_pwwn.raw_wwn[2],
13197 13182 gan_resp->gan_pwwn.raw_wwn[3],
13198 13183 gan_resp->gan_pwwn.raw_wwn[4],
13199 13184 gan_resp->gan_pwwn.raw_wwn[5],
13200 13185 gan_resp->gan_pwwn.raw_wwn[6],
13201 13186 gan_resp->gan_pwwn.raw_wwn[7],
13202 13187
13203 13188 gan_resp->gan_nwwn.raw_wwn[0],
13204 13189 gan_resp->gan_nwwn.raw_wwn[1],
13205 13190 gan_resp->gan_nwwn.raw_wwn[2],
13206 13191 gan_resp->gan_nwwn.raw_wwn[3],
13207 13192 gan_resp->gan_nwwn.raw_wwn[4],
13208 13193 gan_resp->gan_nwwn.raw_wwn[5],
13209 13194 gan_resp->gan_nwwn.raw_wwn[6],
13210 13195 gan_resp->gan_nwwn.raw_wwn[7]);
13211 13196
13212 13197 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13213 13198 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13214 13199 DDI_DEV_AUTOINCR);
13215 13200
13216 13201 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13217 13202 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13218 13203 DDI_DEV_AUTOINCR);
13219 13204
13220 13205 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13221 13206 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13222 13207 "pd %x", port->fp_port_id.port_id, d_id.port_id);
13223 13208 pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13224 13209 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13225 13210 }
13226 13211 if (pd != NULL) {
13227 13212 fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13228 13213 pd, gan_resp);
13229 13214 }
13230 13215
13231 13216 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13232 13217 *((int *)ns_cmd->ns_data_buf) += 1;
13233 13218 }
13234 13219
13235 13220 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13236 13221 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13237 13222
13238 13223 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13239 13224 fc_port_dev_t *userbuf;
13240 13225
13241 13226 userbuf = ((fc_port_dev_t *)
13242 13227 ns_cmd->ns_data_buf) +
13243 13228 ns_cmd->ns_gan_index++;
13244 13229
13245 13230 userbuf->dev_did = d_id;
13246 13231
13247 13232 FC_GET_RSP(port, pkt->pkt_resp_acc,
13248 13233 (uint8_t *)userbuf->dev_type,
13249 13234 (uint8_t *)gan_resp->gan_fc4types,
13250 13235 sizeof (userbuf->dev_type),
13251 13236 DDI_DEV_AUTOINCR);
13252 13237
13253 13238 userbuf->dev_nwwn = nwwn;
13254 13239 userbuf->dev_pwwn = pwwn;
13255 13240
13256 13241 if (pd != NULL) {
13257 13242 mutex_enter(&pd->pd_mutex);
13258 13243 userbuf->dev_state = pd->pd_state;
13259 13244 userbuf->dev_hard_addr =
13260 13245 pd->pd_hard_addr;
13261 13246 mutex_exit(&pd->pd_mutex);
13262 13247 } else {
13263 13248 userbuf->dev_state =
13264 13249 PORT_DEVICE_INVALID;
13265 13250 }
13266 13251 } else if (ns_cmd->ns_flags &
13267 13252 FCTL_NS_BUF_IS_FC_PORTMAP) {
13268 13253 fc_portmap_t *map;
13269 13254
13270 13255 map = ((fc_portmap_t *)
13271 13256 ns_cmd->ns_data_buf) +
13272 13257 ns_cmd->ns_gan_index++;
13273 13258
13274 13259 /*
13275 13260 * First fill it like any new map
13276 13261 * and update the port device info
13277 13262 * below.
13278 13263 */
13279 13264 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13280 13265 map, gan_resp, d_id.port_id);
13281 13266 if (pd != NULL) {
13282 13267 fctl_copy_portmap(map, pd);
13283 13268 } else {
13284 13269 map->map_state = PORT_DEVICE_INVALID;
13285 13270 map->map_type = PORT_DEVICE_NOCHANGE;
13286 13271 }
13287 13272 } else {
13288 13273 caddr_t dst_ptr;
13289 13274
13290 13275 dst_ptr = ns_cmd->ns_data_buf +
13291 13276 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13292 13277
13293 13278 FC_GET_RSP(port, pkt->pkt_resp_acc,
13294 13279 (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13295 13280 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13296 13281 }
13297 13282 } else {
13298 13283 ns_cmd->ns_gan_index++;
13299 13284 }
13300 13285 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13301 13286 fp_iodone(cmd);
13302 13287 return;
13303 13288 }
13304 13289 }
13305 13290
13306 13291 gan_req.pid = d_id;
13307 13292
13308 13293 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13309 13294 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13310 13295 sizeof (gan_req), DDI_DEV_AUTOINCR);
13311 13296
13312 13297 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13313 13298 pkt->pkt_state = FC_PKT_TRAN_ERROR;
13314 13299 fp_iodone(cmd);
13315 13300 } else {
13316 13301 mutex_enter(&port->fp_mutex);
13317 13302 port->fp_out_fpcmds++;
13318 13303 mutex_exit(&port->fp_mutex);
13319 13304 }
13320 13305 }
13321 13306
13322 13307
13323 13308 /*
13324 13309 * Handle NS Query interrupt
13325 13310 */
13326 13311 static void
13327 13312 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13328 13313 {
13329 13314 fp_cmd_t *cmd;
13330 13315 fc_local_port_t *port;
13331 13316 caddr_t src_ptr;
13332 13317 uint32_t xfer_len;
13333 13318
13334 13319 cmd = pkt->pkt_ulp_private;
13335 13320 port = cmd->cmd_port;
13336 13321
13337 13322 xfer_len = ns_cmd->ns_resp_size;
13338 13323
13339 13324 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13340 13325 ns_cmd->ns_cmd_code, xfer_len);
13341 13326
13342 13327 if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13343 13328 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13344 13329
13345 13330 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13346 13331 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13347 13332 }
13348 13333
13349 13334 if (xfer_len <= ns_cmd->ns_data_len) {
13350 13335 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13351 13336 FC_GET_RSP(port, pkt->pkt_resp_acc,
13352 13337 (uint8_t *)ns_cmd->ns_data_buf,
13353 13338 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13354 13339 }
13355 13340
13356 13341 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13357 13342 ASSERT(ns_cmd->ns_pd != NULL);
13358 13343
13359 13344 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13360 13345 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13361 13346 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13362 13347 }
13363 13348 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13364 13349 }
13365 13350
13366 13351 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13367 13352 fctl_free_ns_cmd(ns_cmd);
13368 13353 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13369 13354 }
13370 13355 fp_iodone(cmd);
13371 13356 }
13372 13357
13373 13358
13374 13359 /*
13375 13360 * Handle unsolicited ADISC ELS request
13376 13361 */
13377 13362 static void
13378 13363 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13379 13364 fc_remote_port_t *pd, job_request_t *job)
13380 13365 {
13381 13366 int rval;
13382 13367 fp_cmd_t *cmd;
13383 13368
13384 13369 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13385 13370 port, pd->pd_port_id.port_id, pd->pd_state, pd);
13386 13371 mutex_enter(&pd->pd_mutex);
13387 13372 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13388 13373 mutex_exit(&pd->pd_mutex);
13389 13374 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13390 13375 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13391 13376 0, KM_SLEEP, pd);
13392 13377 if (cmd != NULL) {
13393 13378 fp_els_rjt_init(port, cmd, buf,
13394 13379 FC_ACTION_NON_RETRYABLE,
13395 13380 FC_REASON_INVALID_LINK_CTRL, job);
13396 13381
13397 13382 if (fp_sendcmd(port, cmd,
13398 13383 port->fp_fca_handle) != FC_SUCCESS) {
13399 13384 fp_free_pkt(cmd);
13400 13385 }
13401 13386 }
13402 13387 }
13403 13388 } else {
13404 13389 mutex_exit(&pd->pd_mutex);
13405 13390 /*
13406 13391 * Yes, yes, we don't have a hard address. But we
13407 13392 * we should still respond. Huh ? Visit 21.19.2
13408 13393 * of FC-PH-2 which essentially says that if an
13409 13394 * NL_Port doesn't have a hard address, or if a port
13410 13395 * does not have FC-AL capability, it shall report
13411 13396 * zeroes in this field.
13412 13397 */
13413 13398 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13414 13399 0, KM_SLEEP, pd);
13415 13400 if (cmd == NULL) {
13416 13401 return;
13417 13402 }
13418 13403 fp_adisc_acc_init(port, cmd, buf, job);
13419 13404 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13420 13405 if (rval != FC_SUCCESS) {
13421 13406 fp_free_pkt(cmd);
13422 13407 }
13423 13408 }
13424 13409 }
13425 13410
13426 13411
13427 13412 /*
13428 13413 * Initialize ADISC response.
13429 13414 */
13430 13415 static void
13431 13416 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13432 13417 job_request_t *job)
13433 13418 {
13434 13419 fc_packet_t *pkt;
13435 13420 la_els_adisc_t payload;
13436 13421
13437 13422 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13438 13423 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13439 13424 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13440 13425 cmd->cmd_retry_count = 1;
13441 13426 cmd->cmd_ulp_pkt = NULL;
13442 13427
13443 13428 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13444 13429 cmd->cmd_job = job;
13445 13430
13446 13431 pkt = &cmd->cmd_pkt;
13447 13432
13448 13433 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13449 13434
13450 13435 payload.ls_code.ls_code = LA_ELS_ACC;
13451 13436 payload.ls_code.mbz = 0;
13452 13437
13453 13438 mutex_enter(&port->fp_mutex);
13454 13439 payload.nport_id = port->fp_port_id;
13455 13440 payload.hard_addr = port->fp_hard_addr;
13456 13441 mutex_exit(&port->fp_mutex);
13457 13442
13458 13443 payload.port_wwn = port->fp_service_params.nport_ww_name;
13459 13444 payload.node_wwn = port->fp_service_params.node_ww_name;
13460 13445
13461 13446 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13462 13447 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13463 13448 }
13464 13449
13465 13450
13466 13451 /*
13467 13452 * Hold and Install the requested ULP drivers
13468 13453 */
13469 13454 static void
13470 13455 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13471 13456 {
13472 13457 int len;
13473 13458 int count;
13474 13459 int data_len;
13475 13460 major_t ulp_major;
13476 13461 caddr_t ulp_name;
13477 13462 caddr_t data_ptr;
13478 13463 caddr_t data_buf;
13479 13464
13480 13465 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13481 13466
13482 13467 data_buf = NULL;
13483 13468 if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13484 13469 DDI_PROP_DONTPASS, "load-ulp-list",
13485 13470 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13486 13471 return;
13487 13472 }
13488 13473
13489 13474 len = strlen(data_buf);
13490 13475 port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13491 13476
13492 13477 data_ptr = data_buf + len + 1;
13493 13478 for (count = 0; count < port->fp_ulp_nload; count++) {
13494 13479 len = strlen(data_ptr) + 1;
13495 13480 ulp_name = kmem_zalloc(len, KM_SLEEP);
13496 13481 bcopy(data_ptr, ulp_name, len);
13497 13482
13498 13483 ulp_major = ddi_name_to_major(ulp_name);
13499 13484
13500 13485 if (ulp_major != (major_t)-1) {
13501 13486 if (modload("drv", ulp_name) < 0) {
13502 13487 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13503 13488 0, NULL, "failed to load %s",
13504 13489 ulp_name);
13505 13490 }
13506 13491 } else {
13507 13492 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13508 13493 "%s isn't a valid driver", ulp_name);
13509 13494 }
13510 13495
13511 13496 kmem_free(ulp_name, len);
13512 13497 data_ptr += len; /* Skip to next field */
13513 13498 }
13514 13499
13515 13500 /*
13516 13501 * Free the memory allocated by DDI
13517 13502 */
13518 13503 if (data_buf != NULL) {
13519 13504 kmem_free(data_buf, data_len);
13520 13505 }
13521 13506 }
13522 13507
13523 13508
13524 13509 /*
13525 13510 * Perform LOGO operation
13526 13511 */
13527 13512 static int
13528 13513 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13529 13514 {
13530 13515 int rval;
13531 13516 fp_cmd_t *cmd;
13532 13517
13533 13518 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13534 13519 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13535 13520
13536 13521 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13537 13522 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13538 13523
13539 13524 mutex_enter(&port->fp_mutex);
13540 13525 mutex_enter(&pd->pd_mutex);
13541 13526
13542 13527 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13543 13528 ASSERT(pd->pd_login_count == 1);
13544 13529
13545 13530 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13546 13531 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13547 13532 cmd->cmd_flags = 0;
13548 13533 cmd->cmd_retry_count = 1;
13549 13534 cmd->cmd_ulp_pkt = NULL;
13550 13535
13551 13536 fp_logo_init(pd, cmd, job);
13552 13537
13553 13538 mutex_exit(&pd->pd_mutex);
13554 13539 mutex_exit(&port->fp_mutex);
13555 13540
13556 13541 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13557 13542 if (rval != FC_SUCCESS) {
13558 13543 fp_iodone(cmd);
13559 13544 }
13560 13545
13561 13546 return (rval);
13562 13547 }
13563 13548
13564 13549
13565 13550 /*
13566 13551 * Perform Port attach callbacks to registered ULPs
13567 13552 */
13568 13553 static void
13569 13554 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13570 13555 {
13571 13556 fp_soft_attach_t *att;
13572 13557
13573 13558 att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13574 13559 att->att_cmd = cmd;
13575 13560 att->att_port = port;
13576 13561
13577 13562 /*
13578 13563 * We need to remember whether or not fctl_busy_port
13579 13564 * succeeded so we know whether or not to call
13580 13565 * fctl_idle_port when the task is complete.
13581 13566 */
13582 13567
13583 13568 if (fctl_busy_port(port) == 0) {
13584 13569 att->att_need_pm_idle = B_TRUE;
13585 13570 } else {
13586 13571 att->att_need_pm_idle = B_FALSE;
13587 13572 }
13588 13573
13589 13574 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13590 13575 att, KM_SLEEP);
13591 13576 }
13592 13577
13593 13578
13594 13579 /*
13595 13580 * Forward state change notifications on to interested ULPs.
13596 13581 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13597 13582 * real work.
13598 13583 */
13599 13584 static int
13600 13585 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13601 13586 {
13602 13587 fc_port_clist_t *clist;
13603 13588
13604 13589 clist = kmem_zalloc(sizeof (*clist), sleep);
13605 13590 if (clist == NULL) {
13606 13591 return (FC_NOMEM);
13607 13592 }
13608 13593
13609 13594 clist->clist_state = statec;
13610 13595
13611 13596 mutex_enter(&port->fp_mutex);
13612 13597 clist->clist_flags = port->fp_topology;
13613 13598 mutex_exit(&port->fp_mutex);
13614 13599
13615 13600 clist->clist_port = (opaque_t)port;
13616 13601 clist->clist_len = 0;
13617 13602 clist->clist_size = 0;
13618 13603 clist->clist_map = NULL;
13619 13604
13620 13605 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13621 13606 clist, KM_SLEEP);
13622 13607
13623 13608 return (FC_SUCCESS);
13624 13609 }
13625 13610
13626 13611
13627 13612 /*
13628 13613 * Get name server map
13629 13614 */
13630 13615 static int
13631 13616 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13632 13617 uint32_t *len, uint32_t sid)
13633 13618 {
13634 13619 int ret;
13635 13620 fctl_ns_req_t *ns_cmd;
13636 13621
13637 13622 /*
13638 13623 * Don't let the allocator do anything for response;
13639 13624 * we have have buffer ready to fillout.
13640 13625 */
13641 13626 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13642 13627 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13643 13628 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13644 13629
13645 13630 ns_cmd->ns_data_len = sizeof (**map) * (*len);
13646 13631 ns_cmd->ns_data_buf = (caddr_t)*map;
13647 13632
13648 13633 ASSERT(ns_cmd != NULL);
13649 13634
13650 13635 ns_cmd->ns_gan_index = 0;
13651 13636 ns_cmd->ns_gan_sid = sid;
13652 13637 ns_cmd->ns_cmd_code = NS_GA_NXT;
13653 13638 ns_cmd->ns_gan_max = *len;
13654 13639
13655 13640 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13656 13641
13657 13642 if (ns_cmd->ns_gan_index != *len) {
13658 13643 *len = ns_cmd->ns_gan_index;
13659 13644 }
13660 13645 ns_cmd->ns_data_len = 0;
13661 13646 ns_cmd->ns_data_buf = NULL;
13662 13647 fctl_free_ns_cmd(ns_cmd);
13663 13648
13664 13649 return (ret);
13665 13650 }
13666 13651
13667 13652
13668 13653 /*
13669 13654 * Create a remote port in Fabric topology by using NS services
13670 13655 */
13671 13656 static fc_remote_port_t *
13672 13657 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13673 13658 {
13674 13659 int rval;
13675 13660 job_request_t *job;
13676 13661 fctl_ns_req_t *ns_cmd;
13677 13662 fc_remote_port_t *pd;
13678 13663
13679 13664 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13680 13665
13681 13666 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13682 13667 port, d_id);
13683 13668
13684 13669 #ifdef DEBUG
13685 13670 mutex_enter(&port->fp_mutex);
13686 13671 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13687 13672 mutex_exit(&port->fp_mutex);
13688 13673 #endif
13689 13674
13690 13675 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13691 13676 if (job == NULL) {
13692 13677 return (NULL);
13693 13678 }
13694 13679
13695 13680 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13696 13681 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13697 13682 FCTL_NS_NO_DATA_BUF), sleep);
13698 13683 if (ns_cmd == NULL) {
13699 13684 return (NULL);
13700 13685 }
13701 13686
13702 13687 job->job_result = FC_SUCCESS;
13703 13688 ns_cmd->ns_gan_max = 1;
13704 13689 ns_cmd->ns_cmd_code = NS_GA_NXT;
13705 13690 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13706 13691 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13707 13692 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13708 13693
13709 13694 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13710 13695 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13711 13696 fctl_free_ns_cmd(ns_cmd);
13712 13697
13713 13698 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13714 13699 fctl_dealloc_job(job);
13715 13700 return (NULL);
13716 13701 }
13717 13702 fctl_dealloc_job(job);
13718 13703
13719 13704 pd = fctl_get_remote_port_by_did(port, d_id);
13720 13705
13721 13706 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13722 13707 port, d_id, pd);
13723 13708
13724 13709 return (pd);
13725 13710 }
13726 13711
13727 13712
13728 13713 /*
13729 13714 * Check for the permissions on an ioctl command. If it is required to have an
13730 13715 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13731 13716 * the ioctl command isn't in one of the list built, shut the door on that too.
13732 13717 *
13733 13718 * Certain ioctls perform hardware accesses in FCA drivers, and it needs
13734 13719 * to be made sure that users open the port for an exclusive access while
13735 13720 * performing those operations.
13736 13721 *
13737 13722 * This can prevent a casual user from inflicting damage on the port by
13738 13723 * sending these ioctls from multiple processes/threads (there is no good
13739 13724 * reason why one would need to do that) without actually realizing how
13740 13725 * expensive such commands could turn out to be.
13741 13726 *
13742 13727 * It is also important to note that, even with an exclusive access,
13743 13728 * multiple threads can share the same file descriptor and fire down
13744 13729 * commands in parallel. To prevent that the driver needs to make sure
13745 13730 * that such commands aren't in progress already. This is taken care of
13746 13731 * in the FP_EXCL_BUSY bit of fp_flag.
13747 13732 */
13748 13733 static int
13749 13734 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13750 13735 {
13751 13736 int ret = FC_FAILURE;
13752 13737 int count;
13753 13738
13754 13739 for (count = 0;
13755 13740 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13756 13741 count++) {
13757 13742 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13758 13743 if (fp_perm_list[count].fp_open_flag & open_flag) {
13759 13744 ret = FC_SUCCESS;
13760 13745 }
13761 13746 break;
13762 13747 }
13763 13748 }
13764 13749
13765 13750 return (ret);
13766 13751 }
13767 13752
13768 13753
13769 13754 /*
13770 13755 * Bind Port driver's unsolicited, state change callbacks
13771 13756 */
13772 13757 static int
13773 13758 fp_bind_callbacks(fc_local_port_t *port)
13774 13759 {
13775 13760 fc_fca_bind_info_t bind_info = {0};
13776 13761 fc_fca_port_info_t *port_info;
13777 13762 int rval = DDI_SUCCESS;
13778 13763 uint16_t class;
13779 13764 int node_namelen, port_namelen;
13780 13765 char *nname = NULL, *pname = NULL;
13781 13766
13782 13767 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13783 13768
13784 13769 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13785 13770 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13786 13771 "node-name", &nname) != DDI_PROP_SUCCESS) {
13787 13772 FP_TRACE(FP_NHEAD1(1, 0),
13788 13773 "fp_bind_callback fail to get node-name");
13789 13774 }
13790 13775 if (nname) {
13791 13776 fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13792 13777 }
13793 13778
13794 13779 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13795 13780 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13796 13781 "port-name", &pname) != DDI_PROP_SUCCESS) {
13797 13782 FP_TRACE(FP_NHEAD1(1, 0),
13798 13783 "fp_bind_callback fail to get port-name");
13799 13784 }
13800 13785 if (pname) {
13801 13786 fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13802 13787 }
13803 13788
13804 13789 if (port->fp_npiv_type == FC_NPIV_PORT) {
13805 13790 bind_info.port_npiv = 1;
13806 13791 }
13807 13792
13808 13793 /*
13809 13794 * fca_bind_port returns the FCA driver's handle for the local
13810 13795 * port instance. If the port number isn't supported it returns NULL.
13811 13796 * It also sets up callback in the FCA for various
13812 13797 * things like state change, ELS etc..
13813 13798 */
13814 13799 bind_info.port_statec_cb = fp_statec_cb;
13815 13800 bind_info.port_unsol_cb = fp_unsol_cb;
13816 13801 bind_info.port_num = port->fp_port_num;
13817 13802 bind_info.port_handle = (opaque_t)port;
13818 13803
13819 13804 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13820 13805
13821 13806 /*
13822 13807 * Hold the port driver mutex as the callbacks are bound until the
13823 13808 * service parameters are properly filled in (in order to be able to
13824 13809 * properly respond to unsolicited ELS requests)
13825 13810 */
13826 13811 mutex_enter(&port->fp_mutex);
13827 13812
13828 13813 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13829 13814 port->fp_fca_dip, port_info, &bind_info);
13830 13815
13831 13816 if (port->fp_fca_handle == NULL) {
13832 13817 rval = DDI_FAILURE;
13833 13818 goto exit;
13834 13819 }
13835 13820
13836 13821 /*
13837 13822 * Only fcoei will set this bit
13838 13823 */
13839 13824 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13840 13825 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13841 13826 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13842 13827 }
13843 13828
13844 13829 port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13845 13830 port->fp_service_params = port_info->pi_login_params;
13846 13831 port->fp_hard_addr = port_info->pi_hard_addr;
13847 13832
13848 13833 /* Copy from the FCA structure to the FP structure */
13849 13834 port->fp_hba_port_attrs = port_info->pi_attrs;
13850 13835
13851 13836 if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13852 13837 port->fp_rnid_init = 1;
13853 13838 bcopy(&port_info->pi_rnid_params.params,
13854 13839 &port->fp_rnid_params,
13855 13840 sizeof (port->fp_rnid_params));
13856 13841 } else {
13857 13842 port->fp_rnid_init = 0;
13858 13843 }
13859 13844
13860 13845 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13861 13846 if (node_namelen) {
13862 13847 bcopy(&port_info->pi_attrs.sym_node_name,
13863 13848 &port->fp_sym_node_name,
13864 13849 node_namelen);
13865 13850 port->fp_sym_node_namelen = node_namelen;
13866 13851 }
13867 13852 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13868 13853 if (port_namelen) {
13869 13854 bcopy(&port_info->pi_attrs.sym_port_name,
13870 13855 &port->fp_sym_port_name,
13871 13856 port_namelen);
13872 13857 port->fp_sym_port_namelen = port_namelen;
13873 13858 }
13874 13859
13875 13860 /* zero out the normally unused fields right away */
13876 13861 port->fp_service_params.ls_code.mbz = 0;
13877 13862 port->fp_service_params.ls_code.ls_code = 0;
13878 13863 bzero(&port->fp_service_params.reserved,
13879 13864 sizeof (port->fp_service_params.reserved));
13880 13865
13881 13866 class = port_info->pi_login_params.class_1.class_opt;
13882 13867 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13883 13868
13884 13869 class = port_info->pi_login_params.class_2.class_opt;
13885 13870 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13886 13871
13887 13872 class = port_info->pi_login_params.class_3.class_opt;
13888 13873 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13889 13874
13890 13875 exit:
13891 13876 if (nname) {
13892 13877 ddi_prop_free(nname);
13893 13878 }
13894 13879 if (pname) {
13895 13880 ddi_prop_free(pname);
13896 13881 }
13897 13882 mutex_exit(&port->fp_mutex);
13898 13883 kmem_free(port_info, sizeof (*port_info));
13899 13884
13900 13885 return (rval);
13901 13886 }
13902 13887
13903 13888
13904 13889 /*
13905 13890 * Retrieve FCA capabilities
13906 13891 */
13907 13892 static void
13908 13893 fp_retrieve_caps(fc_local_port_t *port)
13909 13894 {
13910 13895 int rval;
13911 13896 int ub_count;
13912 13897 fc_fcp_dma_t fcp_dma;
13913 13898 fc_reset_action_t action;
13914 13899 fc_dma_behavior_t dma_behavior;
13915 13900
13916 13901 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13917 13902
13918 13903 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13919 13904 FC_CAP_UNSOL_BUF, &ub_count);
13920 13905
13921 13906 switch (rval) {
13922 13907 case FC_CAP_FOUND:
13923 13908 case FC_CAP_SETTABLE:
13924 13909 switch (ub_count) {
13925 13910 case 0:
13926 13911 break;
13927 13912
13928 13913 case -1:
13929 13914 ub_count = fp_unsol_buf_count;
13930 13915 break;
13931 13916
13932 13917 default:
13933 13918 /* 1/4th of total buffers is my share */
13934 13919 ub_count =
13935 13920 (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13936 13921 break;
13937 13922 }
13938 13923 break;
13939 13924
13940 13925 default:
13941 13926 ub_count = 0;
13942 13927 break;
13943 13928 }
13944 13929
13945 13930 mutex_enter(&port->fp_mutex);
13946 13931 port->fp_ub_count = ub_count;
13947 13932 mutex_exit(&port->fp_mutex);
13948 13933
13949 13934 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13950 13935 FC_CAP_POST_RESET_BEHAVIOR, &action);
13951 13936
13952 13937 switch (rval) {
13953 13938 case FC_CAP_FOUND:
13954 13939 case FC_CAP_SETTABLE:
13955 13940 switch (action) {
13956 13941 case FC_RESET_RETURN_NONE:
13957 13942 case FC_RESET_RETURN_ALL:
13958 13943 case FC_RESET_RETURN_OUTSTANDING:
13959 13944 break;
13960 13945
13961 13946 default:
13962 13947 action = FC_RESET_RETURN_NONE;
13963 13948 break;
13964 13949 }
13965 13950 break;
13966 13951
13967 13952 default:
13968 13953 action = FC_RESET_RETURN_NONE;
13969 13954 break;
13970 13955 }
13971 13956 mutex_enter(&port->fp_mutex);
13972 13957 port->fp_reset_action = action;
13973 13958 mutex_exit(&port->fp_mutex);
13974 13959
13975 13960 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13976 13961 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13977 13962
13978 13963 switch (rval) {
13979 13964 case FC_CAP_FOUND:
13980 13965 switch (dma_behavior) {
13981 13966 case FC_ALLOW_STREAMING:
13982 13967 /* FALLTHROUGH */
13983 13968 case FC_NO_STREAMING:
13984 13969 break;
13985 13970
13986 13971 default:
13987 13972 /*
13988 13973 * If capability was found and the value
13989 13974 * was incorrect assume the worst
13990 13975 */
13991 13976 dma_behavior = FC_NO_STREAMING;
13992 13977 break;
13993 13978 }
13994 13979 break;
13995 13980
13996 13981 default:
13997 13982 /*
13998 13983 * If capability was not defined - allow streaming; existing
13999 13984 * FCAs should not be affected.
14000 13985 */
14001 13986 dma_behavior = FC_ALLOW_STREAMING;
14002 13987 break;
14003 13988 }
14004 13989 mutex_enter(&port->fp_mutex);
14005 13990 port->fp_dma_behavior = dma_behavior;
14006 13991 mutex_exit(&port->fp_mutex);
14007 13992
14008 13993 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
14009 13994 FC_CAP_FCP_DMA, &fcp_dma);
14010 13995
14011 13996 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
14012 13997 fcp_dma != FC_DVMA_SPACE)) {
14013 13998 fcp_dma = FC_DVMA_SPACE;
14014 13999 }
14015 14000
14016 14001 mutex_enter(&port->fp_mutex);
14017 14002 port->fp_fcp_dma = fcp_dma;
14018 14003 mutex_exit(&port->fp_mutex);
14019 14004 }
14020 14005
14021 14006
14022 14007 /*
14023 14008 * Handle Domain, Area changes in the Fabric.
14024 14009 */
14025 14010 static void
14026 14011 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
14027 14012 job_request_t *job, int sleep)
14028 14013 {
14029 14014 #ifdef DEBUG
14030 14015 uint32_t dcnt;
14031 14016 #endif
14032 14017 int rval;
14033 14018 int send;
14034 14019 int index;
14035 14020 int listindex;
14036 14021 int login;
14037 14022 int job_flags;
14038 14023 char ww_name[17];
14039 14024 uint32_t d_id;
14040 14025 uint32_t count;
14041 14026 fctl_ns_req_t *ns_cmd;
14042 14027 fc_portmap_t *list;
14043 14028 fc_orphan_t *orp;
14044 14029 fc_orphan_t *norp;
14045 14030 fc_orphan_t *prev;
14046 14031 fc_remote_port_t *pd;
14047 14032 fc_remote_port_t *npd;
14048 14033 struct pwwn_hash *head;
14049 14034
14050 14035 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14051 14036 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14052 14037 0, sleep);
14053 14038 if (ns_cmd == NULL) {
14054 14039 mutex_enter(&port->fp_mutex);
14055 14040 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14056 14041 --port->fp_rscn_count;
14057 14042 }
14058 14043 mutex_exit(&port->fp_mutex);
14059 14044
14060 14045 return;
14061 14046 }
14062 14047 ns_cmd->ns_cmd_code = NS_GID_PN;
14063 14048
14064 14049 /*
14065 14050 * We need to get a new count of devices from the
14066 14051 * name server, which will also create any new devices
14067 14052 * as needed.
14068 14053 */
14069 14054
14070 14055 (void) fp_ns_get_devcount(port, job, 1, sleep);
14071 14056
14072 14057 FP_TRACE(FP_NHEAD1(3, 0),
14073 14058 "fp_validate_area_domain: get_devcount found %d devices",
14074 14059 port->fp_total_devices);
14075 14060
14076 14061 mutex_enter(&port->fp_mutex);
14077 14062
14078 14063 for (count = index = 0; index < pwwn_table_size; index++) {
14079 14064 head = &port->fp_pwwn_table[index];
14080 14065 pd = head->pwwn_head;
14081 14066 while (pd != NULL) {
14082 14067 mutex_enter(&pd->pd_mutex);
14083 14068 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14084 14069 if ((pd->pd_port_id.port_id & mask) == id &&
14085 14070 pd->pd_recepient == PD_PLOGI_INITIATOR) {
14086 14071 count++;
14087 14072 pd->pd_type = PORT_DEVICE_OLD;
14088 14073 pd->pd_flags = PD_ELS_MARK;
14089 14074 }
14090 14075 }
14091 14076 mutex_exit(&pd->pd_mutex);
14092 14077 pd = pd->pd_wwn_hnext;
14093 14078 }
14094 14079 }
14095 14080
14096 14081 #ifdef DEBUG
14097 14082 dcnt = count;
14098 14083 #endif /* DEBUG */
14099 14084
14100 14085 /*
14101 14086 * Since port->fp_orphan_count is declared an 'int' it is
14102 14087 * theoretically possible that the count could go negative.
14103 14088 *
14104 14089 * This would be bad and if that happens we really do want
14105 14090 * to know.
14106 14091 */
14107 14092
14108 14093 ASSERT(port->fp_orphan_count >= 0);
14109 14094
14110 14095 count += port->fp_orphan_count;
14111 14096
14112 14097 /*
14113 14098 * We add the port->fp_total_devices value to the count
14114 14099 * in the case where our port is newly attached. This is
14115 14100 * because we haven't done any discovery and we don't have
14116 14101 * any orphans in the port's orphan list. If we do not do
14117 14102 * this addition to count then we won't alloc enough kmem
14118 14103 * to do discovery with.
14119 14104 */
14120 14105
14121 14106 if (count == 0) {
14122 14107 count += port->fp_total_devices;
14123 14108 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14124 14109 "0x%x orphans found, using 0x%x",
14125 14110 port->fp_orphan_count, count);
14126 14111 }
14127 14112
14128 14113 mutex_exit(&port->fp_mutex);
14129 14114
14130 14115 /*
14131 14116 * Allocate the change list
14132 14117 */
14133 14118
14134 14119 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14135 14120 if (list == NULL) {
14136 14121 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14137 14122 " Not enough memory to service RSCNs"
14138 14123 " for %d ports, continuing...", count);
14139 14124
14140 14125 fctl_free_ns_cmd(ns_cmd);
14141 14126
14142 14127 mutex_enter(&port->fp_mutex);
14143 14128 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14144 14129 --port->fp_rscn_count;
14145 14130 }
14146 14131 mutex_exit(&port->fp_mutex);
14147 14132
14148 14133 return;
14149 14134 }
14150 14135
14151 14136 /*
14152 14137 * Attempt to validate or invalidate the devices that were
14153 14138 * already in the pwwn hash table.
14154 14139 */
14155 14140
14156 14141 mutex_enter(&port->fp_mutex);
14157 14142 for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14158 14143 head = &port->fp_pwwn_table[index];
14159 14144 npd = head->pwwn_head;
14160 14145
14161 14146 while ((pd = npd) != NULL) {
14162 14147 npd = pd->pd_wwn_hnext;
14163 14148
14164 14149 mutex_enter(&pd->pd_mutex);
14165 14150 if ((pd->pd_port_id.port_id & mask) == id &&
14166 14151 pd->pd_flags == PD_ELS_MARK) {
14167 14152 la_wwn_t *pwwn;
14168 14153
14169 14154 job->job_result = FC_SUCCESS;
14170 14155
14171 14156 ((ns_req_gid_pn_t *)
14172 14157 (ns_cmd->ns_cmd_buf))->pwwn =
14173 14158 pd->pd_port_name;
14174 14159
14175 14160 pwwn = &pd->pd_port_name;
14176 14161 d_id = pd->pd_port_id.port_id;
14177 14162
14178 14163 mutex_exit(&pd->pd_mutex);
14179 14164 mutex_exit(&port->fp_mutex);
14180 14165
14181 14166 rval = fp_ns_query(port, ns_cmd, job, 1,
14182 14167 sleep);
14183 14168 if (rval != FC_SUCCESS) {
14184 14169 fc_wwn_to_str(pwwn, ww_name);
14185 14170
14186 14171 FP_TRACE(FP_NHEAD1(3, 0),
14187 14172 "AREA RSCN: PD disappeared; "
14188 14173 "d_id=%x, PWWN=%s", d_id, ww_name);
14189 14174
14190 14175 FP_TRACE(FP_NHEAD2(9, 0),
14191 14176 "N_x Port with D_ID=%x,"
14192 14177 " PWWN=%s disappeared from fabric",
14193 14178 d_id, ww_name);
14194 14179
14195 14180 fp_fillout_old_map(list + listindex++,
14196 14181 pd, 1);
14197 14182 } else {
14198 14183 fctl_copy_portmap(list + listindex++,
14199 14184 pd);
14200 14185
14201 14186 mutex_enter(&pd->pd_mutex);
14202 14187 pd->pd_flags = PD_ELS_IN_PROGRESS;
14203 14188 mutex_exit(&pd->pd_mutex);
14204 14189 }
14205 14190
14206 14191 mutex_enter(&port->fp_mutex);
14207 14192 } else {
14208 14193 mutex_exit(&pd->pd_mutex);
14209 14194 }
14210 14195 }
14211 14196 }
14212 14197
14213 14198 mutex_exit(&port->fp_mutex);
14214 14199
14215 14200 ASSERT(listindex == dcnt);
14216 14201
14217 14202 job->job_counter = listindex;
14218 14203 job_flags = job->job_flags;
14219 14204 job->job_flags |= JOB_TYPE_FP_ASYNC;
14220 14205
14221 14206 /*
14222 14207 * Login (if we were the initiator) or validate devices in the
14223 14208 * port map.
14224 14209 */
14225 14210
14226 14211 for (index = 0; index < listindex; index++) {
14227 14212 pd = list[index].map_pd;
14228 14213
14229 14214 mutex_enter(&pd->pd_mutex);
14230 14215 ASSERT((pd->pd_port_id.port_id & mask) == id);
14231 14216
14232 14217 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14233 14218 ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14234 14219 mutex_exit(&pd->pd_mutex);
14235 14220 fp_jobdone(job);
14236 14221 continue;
14237 14222 }
14238 14223
14239 14224 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14240 14225 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14241 14226 d_id = pd->pd_port_id.port_id;
14242 14227 mutex_exit(&pd->pd_mutex);
14243 14228
14244 14229 if ((d_id & mask) == id && send) {
14245 14230 if (login) {
14246 14231 FP_TRACE(FP_NHEAD1(6, 0),
14247 14232 "RSCN and PLOGI request;"
14248 14233 " pd=%p, job=%p d_id=%x, index=%d", pd,
14249 14234 job, d_id, index);
14250 14235
14251 14236 rval = fp_port_login(port, d_id, job,
14252 14237 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14253 14238 if (rval != FC_SUCCESS) {
14254 14239 mutex_enter(&pd->pd_mutex);
14255 14240 pd->pd_flags = PD_IDLE;
14256 14241 mutex_exit(&pd->pd_mutex);
14257 14242
14258 14243 job->job_result = rval;
14259 14244 fp_jobdone(job);
14260 14245 }
14261 14246 FP_TRACE(FP_NHEAD1(1, 0),
14262 14247 "PLOGI succeeded:no skip(1) for "
14263 14248 "D_ID %x", d_id);
14264 14249 list[index].map_flags |=
14265 14250 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14266 14251 } else {
14267 14252 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14268 14253 " pd=%p, job=%p d_id=%x, index=%d", pd,
14269 14254 job, d_id, index);
14270 14255
14271 14256 rval = fp_ns_validate_device(port, pd, job,
14272 14257 0, sleep);
14273 14258 if (rval != FC_SUCCESS) {
14274 14259 fp_jobdone(job);
14275 14260 }
14276 14261 mutex_enter(&pd->pd_mutex);
14277 14262 pd->pd_flags = PD_IDLE;
14278 14263 mutex_exit(&pd->pd_mutex);
14279 14264 }
14280 14265 } else {
14281 14266 FP_TRACE(FP_NHEAD1(6, 0),
14282 14267 "RSCN and NO request sent; pd=%p,"
14283 14268 " d_id=%x, index=%d", pd, d_id, index);
14284 14269
14285 14270 mutex_enter(&pd->pd_mutex);
14286 14271 pd->pd_flags = PD_IDLE;
14287 14272 mutex_exit(&pd->pd_mutex);
14288 14273
14289 14274 fp_jobdone(job);
14290 14275 }
14291 14276 }
14292 14277
14293 14278 if (listindex) {
14294 14279 fctl_jobwait(job);
14295 14280 }
14296 14281 job->job_flags = job_flags;
14297 14282
14298 14283 /*
14299 14284 * Orphan list validation.
14300 14285 */
14301 14286 mutex_enter(&port->fp_mutex);
14302 14287 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14303 14288 orp != NULL; orp = norp) {
14304 14289 norp = orp->orp_next;
14305 14290 mutex_exit(&port->fp_mutex);
14306 14291
14307 14292 job->job_counter = 1;
14308 14293 job->job_result = FC_SUCCESS;
14309 14294 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14310 14295
14311 14296 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14312 14297
14313 14298 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14314 14299 ((ns_resp_gid_pn_t *)
14315 14300 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14316 14301
14317 14302 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14318 14303 if (rval == FC_SUCCESS) {
14319 14304 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14320 14305 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14321 14306 if (pd != NULL) {
14322 14307 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14323 14308
14324 14309 FP_TRACE(FP_NHEAD1(6, 0),
14325 14310 "RSCN and ORPHAN list "
14326 14311 "success; d_id=%x, PWWN=%s", d_id, ww_name);
14327 14312
14328 14313 FP_TRACE(FP_NHEAD2(6, 0),
14329 14314 "N_x Port with D_ID=%x, PWWN=%s reappeared"
14330 14315 " in fabric", d_id, ww_name);
14331 14316
14332 14317 mutex_enter(&port->fp_mutex);
14333 14318 if (prev) {
14334 14319 prev->orp_next = orp->orp_next;
14335 14320 } else {
14336 14321 ASSERT(orp == port->fp_orphan_list);
14337 14322 port->fp_orphan_list = orp->orp_next;
14338 14323 }
14339 14324 port->fp_orphan_count--;
14340 14325 mutex_exit(&port->fp_mutex);
14341 14326
14342 14327 kmem_free(orp, sizeof (*orp));
14343 14328 fctl_copy_portmap(list + listindex++, pd);
14344 14329 } else {
14345 14330 prev = orp;
14346 14331 }
14347 14332 } else {
14348 14333 prev = orp;
14349 14334 }
14350 14335 mutex_enter(&port->fp_mutex);
14351 14336 }
14352 14337 mutex_exit(&port->fp_mutex);
14353 14338
14354 14339 /*
14355 14340 * One more pass through the list to delist old devices from
14356 14341 * the d_id and pwwn tables and possibly add to the orphan list.
14357 14342 */
14358 14343
14359 14344 for (index = 0; index < listindex; index++) {
14360 14345 pd = list[index].map_pd;
14361 14346 ASSERT(pd != NULL);
14362 14347
14363 14348 /*
14364 14349 * Update PLOGI results; For NS validation
14365 14350 * of orphan list, it is redundant
14366 14351 *
14367 14352 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14368 14353 * appropriate as fctl_copy_portmap() will clear map_flags.
14369 14354 */
14370 14355 if (list[index].map_flags &
14371 14356 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14372 14357 fctl_copy_portmap(list + index, pd);
14373 14358 list[index].map_flags |=
14374 14359 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14375 14360 } else {
14376 14361 fctl_copy_portmap(list + index, pd);
14377 14362 }
14378 14363
14379 14364 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14380 14365 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14381 14366 pd, pd->pd_port_id.port_id,
14382 14367 pd->pd_port_name.raw_wwn[0],
14383 14368 pd->pd_port_name.raw_wwn[1],
14384 14369 pd->pd_port_name.raw_wwn[2],
14385 14370 pd->pd_port_name.raw_wwn[3],
14386 14371 pd->pd_port_name.raw_wwn[4],
14387 14372 pd->pd_port_name.raw_wwn[5],
14388 14373 pd->pd_port_name.raw_wwn[6],
14389 14374 pd->pd_port_name.raw_wwn[7]);
14390 14375
14391 14376 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14392 14377 "results continued, pd=%p type=%x, flags=%x, state=%x",
14393 14378 pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14394 14379
14395 14380 mutex_enter(&pd->pd_mutex);
14396 14381 if (pd->pd_type == PORT_DEVICE_OLD) {
14397 14382 int initiator;
14398 14383
14399 14384 pd->pd_flags = PD_IDLE;
14400 14385 initiator = (pd->pd_recepient ==
14401 14386 PD_PLOGI_INITIATOR) ? 1 : 0;
14402 14387
14403 14388 mutex_exit(&pd->pd_mutex);
14404 14389
14405 14390 mutex_enter(&port->fp_mutex);
14406 14391 mutex_enter(&pd->pd_mutex);
14407 14392
14408 14393 pd->pd_state = PORT_DEVICE_INVALID;
14409 14394 fctl_delist_did_table(port, pd);
14410 14395 fctl_delist_pwwn_table(port, pd);
14411 14396
14412 14397 mutex_exit(&pd->pd_mutex);
14413 14398 mutex_exit(&port->fp_mutex);
14414 14399
14415 14400 if (initiator) {
14416 14401 (void) fctl_add_orphan(port, pd, sleep);
14417 14402 }
14418 14403 list[index].map_pd = pd;
14419 14404 } else {
14420 14405 ASSERT(pd->pd_flags == PD_IDLE);
14421 14406 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14422 14407 /*
14423 14408 * Reset LOGO tolerance to zero
14424 14409 */
14425 14410 fctl_tc_reset(&pd->pd_logo_tc);
14426 14411 }
14427 14412 mutex_exit(&pd->pd_mutex);
14428 14413 }
14429 14414 }
14430 14415
14431 14416 if (ns_cmd) {
14432 14417 fctl_free_ns_cmd(ns_cmd);
14433 14418 }
14434 14419 if (listindex) {
14435 14420 (void) fp_ulp_devc_cb(port, list, listindex, count,
14436 14421 sleep, 0);
14437 14422 } else {
14438 14423 kmem_free(list, sizeof (*list) * count);
14439 14424
14440 14425 mutex_enter(&port->fp_mutex);
14441 14426 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14442 14427 --port->fp_rscn_count;
14443 14428 }
14444 14429 mutex_exit(&port->fp_mutex);
14445 14430 }
14446 14431 }
14447 14432
14448 14433
14449 14434 /*
14450 14435 * Work hard to make sense out of an RSCN page.
14451 14436 */
14452 14437 static void
14453 14438 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14454 14439 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14455 14440 int *listindex, int sleep)
14456 14441 {
14457 14442 int rval;
14458 14443 char ww_name[17];
14459 14444 la_wwn_t *pwwn;
14460 14445 fc_remote_port_t *pwwn_pd;
14461 14446 fc_remote_port_t *did_pd;
14462 14447
14463 14448 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14464 14449
14465 14450 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14466 14451 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14467 14452 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14468 14453
14469 14454 if (did_pd != NULL) {
14470 14455 mutex_enter(&did_pd->pd_mutex);
14471 14456 if (did_pd->pd_flags != PD_IDLE) {
14472 14457 mutex_exit(&did_pd->pd_mutex);
14473 14458 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14474 14459 "PD is BUSY; port=%p, d_id=%x, pd=%p",
14475 14460 port, page->aff_d_id, did_pd);
14476 14461 return;
14477 14462 }
14478 14463 did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14479 14464 mutex_exit(&did_pd->pd_mutex);
14480 14465 }
14481 14466
14482 14467 job->job_counter = 1;
14483 14468
14484 14469 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14485 14470
14486 14471 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14487 14472 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14488 14473
14489 14474 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14490 14475 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14491 14476
14492 14477 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14493 14478 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14494 14479 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14495 14480 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14496 14481 ns_cmd->ns_resp_hdr.ct_expln);
14497 14482
14498 14483 job->job_counter = 1;
14499 14484
14500 14485 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14501 14486 /*
14502 14487 * What this means is that the D_ID
14503 14488 * disappeared from the Fabric.
14504 14489 */
14505 14490 if (did_pd == NULL) {
14506 14491 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14507 14492 " NULL PD disappeared, rval=%x", rval);
14508 14493 return;
14509 14494 }
14510 14495
14511 14496 fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14512 14497
14513 14498 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14514 14499 (uint32_t)(uintptr_t)job->job_cb_arg;
14515 14500
14516 14501 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14517 14502
14518 14503 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14519 14504 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14520 14505
14521 14506 FP_TRACE(FP_NHEAD2(9, 0),
14522 14507 "GPN_ID for D_ID=%x failed", page->aff_d_id);
14523 14508
14524 14509 FP_TRACE(FP_NHEAD2(9, 0),
14525 14510 "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14526 14511 " fabric", page->aff_d_id, ww_name);
14527 14512
14528 14513 mutex_enter(&did_pd->pd_mutex);
14529 14514 did_pd->pd_flags = PD_IDLE;
14530 14515 mutex_exit(&did_pd->pd_mutex);
14531 14516
14532 14517 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14533 14518 "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14534 14519
14535 14520 return;
14536 14521 }
14537 14522
14538 14523 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14539 14524
14540 14525 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14541 14526 /*
14542 14527 * There is no change. Do PLOGI again and add it to
14543 14528 * ULP portmap baggage and return. Note: When RSCNs
14544 14529 * arrive with per page states, the need for PLOGI
14545 14530 * can be determined correctly.
14546 14531 */
14547 14532 mutex_enter(&pwwn_pd->pd_mutex);
14548 14533 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14549 14534 mutex_exit(&pwwn_pd->pd_mutex);
14550 14535
14551 14536 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14552 14537 (uint32_t)(uintptr_t)job->job_cb_arg;
14553 14538
14554 14539 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14555 14540
14556 14541 mutex_enter(&pwwn_pd->pd_mutex);
14557 14542 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14558 14543 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14559 14544 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14560 14545 mutex_exit(&pwwn_pd->pd_mutex);
14561 14546
14562 14547 rval = fp_port_login(port, page->aff_d_id, job,
14563 14548 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14564 14549 if (rval == FC_SUCCESS) {
14565 14550 fp_jobwait(job);
14566 14551 rval = job->job_result;
14567 14552
14568 14553 /*
14569 14554 * Reset LOGO tolerance to zero
14570 14555 * Also we are the PLOGI initiator now.
14571 14556 */
14572 14557 mutex_enter(&pwwn_pd->pd_mutex);
14573 14558 fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14574 14559 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14575 14560 mutex_exit(&pwwn_pd->pd_mutex);
14576 14561 }
14577 14562
14578 14563 if (rval == FC_SUCCESS) {
14579 14564 struct fc_portmap *map =
14580 14565 listptr + *listindex - 1;
14581 14566
14582 14567 FP_TRACE(FP_NHEAD1(1, 0),
14583 14568 "PLOGI succeeded: no skip(2)"
14584 14569 " for D_ID %x", page->aff_d_id);
14585 14570 map->map_flags |=
14586 14571 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14587 14572 } else {
14588 14573 FP_TRACE(FP_NHEAD2(9, rval),
14589 14574 "PLOGI to D_ID=%x failed", page->aff_d_id);
14590 14575
14591 14576 FP_TRACE(FP_NHEAD2(9, 0),
14592 14577 "N_x Port with D_ID=%x, PWWN=%s"
14593 14578 " disappeared from fabric",
14594 14579 page->aff_d_id, ww_name);
14595 14580
14596 14581 fp_fillout_old_map(listptr +
14597 14582 *listindex - 1, pwwn_pd, 0);
14598 14583 }
14599 14584 } else {
14600 14585 mutex_exit(&pwwn_pd->pd_mutex);
14601 14586 }
14602 14587
14603 14588 mutex_enter(&did_pd->pd_mutex);
14604 14589 did_pd->pd_flags = PD_IDLE;
14605 14590 mutex_exit(&did_pd->pd_mutex);
14606 14591
14607 14592 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14608 14593 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14609 14594 job->job_result, pwwn_pd);
14610 14595
14611 14596 return;
14612 14597 }
14613 14598
14614 14599 if (did_pd == NULL && pwwn_pd == NULL) {
14615 14600
14616 14601 fc_orphan_t *orp = NULL;
14617 14602 fc_orphan_t *norp = NULL;
14618 14603 fc_orphan_t *prev = NULL;
14619 14604
14620 14605 /*
14621 14606 * Hunt down the orphan list before giving up.
14622 14607 */
14623 14608
14624 14609 mutex_enter(&port->fp_mutex);
14625 14610 if (port->fp_orphan_count) {
14626 14611
14627 14612 for (orp = port->fp_orphan_list; orp; orp = norp) {
14628 14613 norp = orp->orp_next;
14629 14614
14630 14615 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14631 14616 prev = orp;
14632 14617 continue;
14633 14618 }
14634 14619
14635 14620 if (prev) {
14636 14621 prev->orp_next = orp->orp_next;
14637 14622 } else {
14638 14623 ASSERT(orp ==
14639 14624 port->fp_orphan_list);
14640 14625 port->fp_orphan_list =
14641 14626 orp->orp_next;
14642 14627 }
14643 14628 port->fp_orphan_count--;
14644 14629 break;
14645 14630 }
14646 14631 }
14647 14632
14648 14633 mutex_exit(&port->fp_mutex);
14649 14634 pwwn_pd = fp_create_remote_port_by_ns(port,
14650 14635 page->aff_d_id, sleep);
14651 14636
14652 14637 if (pwwn_pd != NULL) {
14653 14638
14654 14639 if (orp) {
14655 14640 fc_wwn_to_str(&orp->orp_pwwn,
14656 14641 ww_name);
14657 14642
14658 14643 FP_TRACE(FP_NHEAD2(9, 0),
14659 14644 "N_x Port with D_ID=%x,"
14660 14645 " PWWN=%s reappeared in fabric",
14661 14646 page->aff_d_id, ww_name);
14662 14647
14663 14648 kmem_free(orp, sizeof (*orp));
14664 14649 }
14665 14650
14666 14651 (listptr + *listindex)->
14667 14652 map_rscn_info.ulp_rscn_count =
14668 14653 (uint32_t)(uintptr_t)job->job_cb_arg;
14669 14654
14670 14655 fctl_copy_portmap(listptr +
14671 14656 (*listindex)++, pwwn_pd);
14672 14657 }
14673 14658
14674 14659 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14675 14660 "Case TWO", page->aff_d_id);
14676 14661
14677 14662 return;
14678 14663 }
14679 14664
14680 14665 if (pwwn_pd != NULL && did_pd == NULL) {
14681 14666 uint32_t old_d_id;
14682 14667 uint32_t d_id = page->aff_d_id;
14683 14668
14684 14669 /*
14685 14670 * What this means is there is a new D_ID for this
14686 14671 * Port WWN. Take out the port device off D_ID
14687 14672 * list and put it back with a new D_ID. Perform
14688 14673 * PLOGI if already logged in.
14689 14674 */
14690 14675 mutex_enter(&port->fp_mutex);
14691 14676 mutex_enter(&pwwn_pd->pd_mutex);
14692 14677
14693 14678 old_d_id = pwwn_pd->pd_port_id.port_id;
14694 14679
14695 14680 fctl_delist_did_table(port, pwwn_pd);
14696 14681
14697 14682 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14698 14683 (uint32_t)(uintptr_t)job->job_cb_arg;
14699 14684
14700 14685 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14701 14686 &d_id, NULL);
14702 14687 fctl_enlist_did_table(port, pwwn_pd);
14703 14688
14704 14689 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14705 14690 " Case THREE, pd=%p,"
14706 14691 " state=%x", pwwn_pd, pwwn_pd->pd_state);
14707 14692
14708 14693 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14709 14694 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14710 14695 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14711 14696
14712 14697 mutex_exit(&pwwn_pd->pd_mutex);
14713 14698 mutex_exit(&port->fp_mutex);
14714 14699
14715 14700 FP_TRACE(FP_NHEAD2(9, 0),
14716 14701 "N_x Port with D_ID=%x, PWWN=%s has a new"
14717 14702 " D_ID=%x now", old_d_id, ww_name, d_id);
14718 14703
14719 14704 rval = fp_port_login(port, page->aff_d_id, job,
14720 14705 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14721 14706 if (rval == FC_SUCCESS) {
14722 14707 fp_jobwait(job);
14723 14708 rval = job->job_result;
14724 14709 }
14725 14710
14726 14711 if (rval != FC_SUCCESS) {
14727 14712 fp_fillout_old_map(listptr +
14728 14713 *listindex - 1, pwwn_pd, 0);
14729 14714 }
14730 14715 } else {
14731 14716 mutex_exit(&pwwn_pd->pd_mutex);
14732 14717 mutex_exit(&port->fp_mutex);
14733 14718 }
14734 14719
14735 14720 return;
14736 14721 }
14737 14722
14738 14723 if (pwwn_pd == NULL && did_pd != NULL) {
14739 14724 fc_portmap_t *ptr;
14740 14725 uint32_t len = 1;
14741 14726 char old_ww_name[17];
14742 14727
14743 14728 mutex_enter(&did_pd->pd_mutex);
14744 14729 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14745 14730 mutex_exit(&did_pd->pd_mutex);
14746 14731
14747 14732 fc_wwn_to_str(pwwn, ww_name);
14748 14733
14749 14734 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14750 14735 (uint32_t)(uintptr_t)job->job_cb_arg;
14751 14736
14752 14737 /*
14753 14738 * What this means is that there is a new Port WWN for
14754 14739 * this D_ID; Mark the Port device as old and provide
14755 14740 * the new PWWN and D_ID combination as new.
14756 14741 */
14757 14742 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14758 14743
14759 14744 FP_TRACE(FP_NHEAD2(9, 0),
14760 14745 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14761 14746 page->aff_d_id, old_ww_name, ww_name);
14762 14747
14763 14748 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14764 14749 (uint32_t)(uintptr_t)job->job_cb_arg;
14765 14750
14766 14751 ptr = listptr + (*listindex)++;
14767 14752
14768 14753 job->job_counter = 1;
14769 14754
14770 14755 if (fp_ns_getmap(port, job, &ptr, &len,
14771 14756 page->aff_d_id - 1) != FC_SUCCESS) {
14772 14757 (*listindex)--;
14773 14758 }
14774 14759
14775 14760 mutex_enter(&did_pd->pd_mutex);
14776 14761 did_pd->pd_flags = PD_IDLE;
14777 14762 mutex_exit(&did_pd->pd_mutex);
14778 14763
14779 14764 return;
14780 14765 }
14781 14766
14782 14767 /*
14783 14768 * A weird case of Port WWN and D_ID existence but not matching up
14784 14769 * between them. Trust your instincts - Take the port device handle
14785 14770 * off Port WWN list, fix it with new Port WWN and put it back, In
14786 14771 * the mean time mark the port device corresponding to the old port
14787 14772 * WWN as OLD.
14788 14773 */
14789 14774 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14790 14775 " did_pd=%p", pwwn_pd, did_pd);
14791 14776
14792 14777 mutex_enter(&port->fp_mutex);
14793 14778 mutex_enter(&pwwn_pd->pd_mutex);
14794 14779
14795 14780 pwwn_pd->pd_type = PORT_DEVICE_OLD;
14796 14781 pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14797 14782 fctl_delist_did_table(port, pwwn_pd);
14798 14783 fctl_delist_pwwn_table(port, pwwn_pd);
14799 14784
14800 14785 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14801 14786 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14802 14787 pwwn_pd->pd_port_id.port_id,
14803 14788
14804 14789 pwwn_pd->pd_port_name.raw_wwn[0],
14805 14790 pwwn_pd->pd_port_name.raw_wwn[1],
14806 14791 pwwn_pd->pd_port_name.raw_wwn[2],
14807 14792 pwwn_pd->pd_port_name.raw_wwn[3],
14808 14793 pwwn_pd->pd_port_name.raw_wwn[4],
14809 14794 pwwn_pd->pd_port_name.raw_wwn[5],
14810 14795 pwwn_pd->pd_port_name.raw_wwn[6],
14811 14796 pwwn_pd->pd_port_name.raw_wwn[7]);
14812 14797
14813 14798 mutex_exit(&pwwn_pd->pd_mutex);
14814 14799 mutex_exit(&port->fp_mutex);
14815 14800
14816 14801 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14817 14802 (uint32_t)(uintptr_t)job->job_cb_arg;
14818 14803
14819 14804 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14820 14805
14821 14806 mutex_enter(&port->fp_mutex);
14822 14807 mutex_enter(&did_pd->pd_mutex);
14823 14808
14824 14809 fctl_delist_pwwn_table(port, did_pd);
14825 14810
14826 14811 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14827 14812 (uint32_t)(uintptr_t)job->job_cb_arg;
14828 14813
14829 14814 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14830 14815 fctl_enlist_pwwn_table(port, did_pd);
14831 14816
14832 14817 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14833 14818 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14834 14819 did_pd->pd_port_id.port_id, did_pd->pd_state,
14835 14820
14836 14821 did_pd->pd_port_name.raw_wwn[0],
14837 14822 did_pd->pd_port_name.raw_wwn[1],
14838 14823 did_pd->pd_port_name.raw_wwn[2],
14839 14824 did_pd->pd_port_name.raw_wwn[3],
14840 14825 did_pd->pd_port_name.raw_wwn[4],
14841 14826 did_pd->pd_port_name.raw_wwn[5],
14842 14827 did_pd->pd_port_name.raw_wwn[6],
14843 14828 did_pd->pd_port_name.raw_wwn[7]);
14844 14829
14845 14830 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14846 14831 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14847 14832 mutex_exit(&did_pd->pd_mutex);
14848 14833 mutex_exit(&port->fp_mutex);
14849 14834
14850 14835 rval = fp_port_login(port, page->aff_d_id, job,
14851 14836 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14852 14837 if (rval == FC_SUCCESS) {
14853 14838 fp_jobwait(job);
14854 14839 if (job->job_result != FC_SUCCESS) {
14855 14840 fp_fillout_old_map(listptr +
14856 14841 *listindex - 1, did_pd, 0);
14857 14842 }
14858 14843 } else {
14859 14844 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14860 14845 }
14861 14846 } else {
14862 14847 mutex_exit(&did_pd->pd_mutex);
14863 14848 mutex_exit(&port->fp_mutex);
14864 14849 }
14865 14850
14866 14851 mutex_enter(&did_pd->pd_mutex);
14867 14852 did_pd->pd_flags = PD_IDLE;
14868 14853 mutex_exit(&did_pd->pd_mutex);
14869 14854 }
14870 14855
14871 14856
14872 14857 /*
14873 14858 * Check with NS for the presence of this port WWN
14874 14859 */
14875 14860 static int
14876 14861 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14877 14862 job_request_t *job, int polled, int sleep)
14878 14863 {
14879 14864 la_wwn_t pwwn;
14880 14865 uint32_t flags;
14881 14866 fctl_ns_req_t *ns_cmd;
14882 14867
14883 14868 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14884 14869 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14885 14870 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14886 14871 flags, sleep);
14887 14872 if (ns_cmd == NULL) {
14888 14873 return (FC_NOMEM);
14889 14874 }
14890 14875
14891 14876 mutex_enter(&pd->pd_mutex);
14892 14877 pwwn = pd->pd_port_name;
14893 14878 mutex_exit(&pd->pd_mutex);
14894 14879
14895 14880 ns_cmd->ns_cmd_code = NS_GID_PN;
14896 14881 ns_cmd->ns_pd = pd;
14897 14882 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14898 14883 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14899 14884 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14900 14885
14901 14886 return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14902 14887 }
14903 14888
14904 14889
14905 14890 /*
14906 14891 * Sanity check the LILP map returned by FCA
14907 14892 */
14908 14893 static int
14909 14894 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14910 14895 {
14911 14896 int count;
14912 14897
14913 14898 if (lilp_map->lilp_length == 0) {
14914 14899 return (FC_FAILURE);
14915 14900 }
14916 14901
14917 14902 for (count = 0; count < lilp_map->lilp_length; count++) {
14918 14903 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14919 14904 FC_SUCCESS) {
14920 14905 return (FC_FAILURE);
14921 14906 }
14922 14907 }
14923 14908
14924 14909 return (FC_SUCCESS);
14925 14910 }
14926 14911
14927 14912
14928 14913 /*
14929 14914 * Sanity check if the AL_PA is a valid address
14930 14915 */
14931 14916 static int
14932 14917 fp_is_valid_alpa(uchar_t al_pa)
14933 14918 {
14934 14919 int count;
14935 14920
14936 14921 for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14937 14922 if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14938 14923 return (FC_SUCCESS);
14939 14924 }
14940 14925 }
14941 14926
14942 14927 return (FC_FAILURE);
14943 14928 }
14944 14929
14945 14930
14946 14931 /*
14947 14932 * Post unsolicited callbacks to ULPs
14948 14933 */
14949 14934 static void
14950 14935 fp_ulp_unsol_cb(void *arg)
14951 14936 {
14952 14937 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg;
14953 14938
14954 14939 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14955 14940 ub_spec->buf->ub_frame.type);
14956 14941 kmem_free(ub_spec, sizeof (*ub_spec));
14957 14942 }
14958 14943
14959 14944
14960 14945 /*
14961 14946 * Perform message reporting in a consistent manner. Unless there is
14962 14947 * a strong reason NOT to use this function (which is very very rare)
14963 14948 * all message reporting should go through this.
14964 14949 */
14965 14950 static void
14966 14951 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14967 14952 fc_packet_t *pkt, const char *fmt, ...)
14968 14953 {
14969 14954 caddr_t buf;
14970 14955 va_list ap;
14971 14956
14972 14957 switch (level) {
14973 14958 case CE_NOTE:
14974 14959 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14975 14960 return;
14976 14961 }
14977 14962 break;
14978 14963
14979 14964 case CE_WARN:
14980 14965 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14981 14966 return;
14982 14967 }
14983 14968 break;
14984 14969 }
14985 14970
14986 14971 buf = kmem_zalloc(256, KM_NOSLEEP);
14987 14972 if (buf == NULL) {
14988 14973 return;
14989 14974 }
14990 14975
14991 14976 (void) sprintf(buf, "fp(%d): ", port->fp_instance);
14992 14977
14993 14978 va_start(ap, fmt);
14994 14979 (void) vsprintf(buf + strlen(buf), fmt, ap);
14995 14980 va_end(ap);
14996 14981
14997 14982 if (fc_errno) {
14998 14983 char *errmsg;
14999 14984
15000 14985 (void) fc_ulp_error(fc_errno, &errmsg);
15001 14986 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
15002 14987 } else {
15003 14988 if (pkt) {
15004 14989 caddr_t state, reason, action, expln;
15005 14990
15006 14991 (void) fc_ulp_pkt_error(pkt, &state, &reason,
15007 14992 &action, &expln);
15008 14993
15009 14994 (void) sprintf(buf + strlen(buf),
15010 14995 " state=%s, reason=%s", state, reason);
15011 14996
15012 14997 if (pkt->pkt_resp_resid) {
15013 14998 (void) sprintf(buf + strlen(buf),
15014 14999 " resp resid=%x\n", pkt->pkt_resp_resid);
15015 15000 }
15016 15001 }
15017 15002 }
15018 15003
15019 15004 switch (dest) {
15020 15005 case FP_CONSOLE_ONLY:
15021 15006 cmn_err(level, "^%s", buf);
15022 15007 break;
15023 15008
15024 15009 case FP_LOG_ONLY:
15025 15010 cmn_err(level, "!%s", buf);
15026 15011 break;
15027 15012
15028 15013 default:
15029 15014 cmn_err(level, "%s", buf);
15030 15015 break;
15031 15016 }
15032 15017
15033 15018 kmem_free(buf, 256);
15034 15019 }
15035 15020
15036 15021 static int
15037 15022 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15038 15023 {
15039 15024 int ret;
15040 15025 uint32_t d_id;
15041 15026 la_wwn_t pwwn;
15042 15027 fc_remote_port_t *pd = NULL;
15043 15028 fc_remote_port_t *held_pd = NULL;
15044 15029 fctl_ns_req_t *ns_cmd;
15045 15030 fc_portmap_t *changelist;
15046 15031
15047 15032 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15048 15033
15049 15034 mutex_enter(&port->fp_mutex);
15050 15035 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15051 15036 mutex_exit(&port->fp_mutex);
15052 15037 job->job_counter = 1;
15053 15038
15054 15039 job->job_result = FC_SUCCESS;
15055 15040
15056 15041 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
15057 15042 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
15058 15043 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
15059 15044
15060 15045 ASSERT(ns_cmd != NULL);
15061 15046
15062 15047 ns_cmd->ns_cmd_code = NS_GID_PN;
15063 15048 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
15064 15049
15065 15050 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
15066 15051
15067 15052 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15068 15053 if (ret != FC_SUCCESS) {
15069 15054 fcio->fcio_errno = ret;
15070 15055 } else {
15071 15056 fcio->fcio_errno = job->job_result;
15072 15057 }
15073 15058 fctl_free_ns_cmd(ns_cmd);
15074 15059 return (EIO);
15075 15060 }
15076 15061 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15077 15062 fctl_free_ns_cmd(ns_cmd);
15078 15063 } else {
15079 15064 mutex_exit(&port->fp_mutex);
15080 15065
15081 15066 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15082 15067 if (held_pd == NULL) {
15083 15068 fcio->fcio_errno = FC_BADWWN;
15084 15069 return (EIO);
15085 15070 }
15086 15071 pd = held_pd;
15087 15072
15088 15073 mutex_enter(&pd->pd_mutex);
15089 15074 d_id = pd->pd_port_id.port_id;
15090 15075 mutex_exit(&pd->pd_mutex);
15091 15076 }
15092 15077
15093 15078 job->job_counter = 1;
15094 15079
15095 15080 pd = fctl_get_remote_port_by_did(port, d_id);
15096 15081
15097 15082 if (pd) {
15098 15083 mutex_enter(&pd->pd_mutex);
15099 15084 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15100 15085 pd->pd_login_count++;
15101 15086 mutex_exit(&pd->pd_mutex);
15102 15087
15103 15088 fcio->fcio_errno = FC_SUCCESS;
15104 15089 if (held_pd) {
15105 15090 fctl_release_remote_port(held_pd);
15106 15091 }
15107 15092
15108 15093 return (0);
15109 15094 }
15110 15095 mutex_exit(&pd->pd_mutex);
15111 15096 } else {
15112 15097 mutex_enter(&port->fp_mutex);
15113 15098 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15114 15099 mutex_exit(&port->fp_mutex);
15115 15100 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15116 15101 if (pd == NULL) {
15117 15102 fcio->fcio_errno = FC_FAILURE;
15118 15103 if (held_pd) {
15119 15104 fctl_release_remote_port(held_pd);
15120 15105 }
15121 15106 return (EIO);
15122 15107 }
15123 15108 } else {
15124 15109 mutex_exit(&port->fp_mutex);
15125 15110 }
15126 15111 }
15127 15112
15128 15113 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15129 15114 job->job_counter = 1;
15130 15115
15131 15116 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15132 15117 KM_SLEEP, pd, NULL);
15133 15118
15134 15119 if (ret != FC_SUCCESS) {
15135 15120 fcio->fcio_errno = ret;
15136 15121 if (held_pd) {
15137 15122 fctl_release_remote_port(held_pd);
15138 15123 }
15139 15124 return (EIO);
15140 15125 }
15141 15126 fp_jobwait(job);
15142 15127
15143 15128 fcio->fcio_errno = job->job_result;
15144 15129
15145 15130 if (held_pd) {
15146 15131 fctl_release_remote_port(held_pd);
15147 15132 }
15148 15133
15149 15134 if (job->job_result != FC_SUCCESS) {
15150 15135 return (EIO);
15151 15136 }
15152 15137
15153 15138 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15154 15139 if (pd == NULL) {
15155 15140 fcio->fcio_errno = FC_BADDEV;
15156 15141 return (ENODEV);
15157 15142 }
15158 15143
15159 15144 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15160 15145
15161 15146 fctl_copy_portmap(changelist, pd);
15162 15147 changelist->map_type = PORT_DEVICE_USER_LOGIN;
15163 15148
15164 15149 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15165 15150
15166 15151 mutex_enter(&pd->pd_mutex);
15167 15152 pd->pd_type = PORT_DEVICE_NOCHANGE;
15168 15153 mutex_exit(&pd->pd_mutex);
15169 15154
15170 15155 fctl_release_remote_port(pd);
15171 15156
15172 15157 return (0);
15173 15158 }
15174 15159
15175 15160
15176 15161 static int
15177 15162 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15178 15163 {
15179 15164 la_wwn_t pwwn;
15180 15165 fp_cmd_t *cmd;
15181 15166 fc_portmap_t *changelist;
15182 15167 fc_remote_port_t *pd;
15183 15168
15184 15169 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15185 15170
15186 15171 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15187 15172 if (pd == NULL) {
15188 15173 fcio->fcio_errno = FC_BADWWN;
15189 15174 return (ENXIO);
15190 15175 }
15191 15176
15192 15177 mutex_enter(&pd->pd_mutex);
15193 15178 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15194 15179 fcio->fcio_errno = FC_LOGINREQ;
15195 15180 mutex_exit(&pd->pd_mutex);
15196 15181
15197 15182 fctl_release_remote_port(pd);
15198 15183
15199 15184 return (EINVAL);
15200 15185 }
15201 15186
15202 15187 ASSERT(pd->pd_login_count >= 1);
15203 15188
15204 15189 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15205 15190 fcio->fcio_errno = FC_FAILURE;
15206 15191 mutex_exit(&pd->pd_mutex);
15207 15192
15208 15193 fctl_release_remote_port(pd);
15209 15194
15210 15195 return (EBUSY);
15211 15196 }
15212 15197
15213 15198 if (pd->pd_login_count > 1) {
15214 15199 pd->pd_login_count--;
15215 15200 fcio->fcio_errno = FC_SUCCESS;
15216 15201 mutex_exit(&pd->pd_mutex);
15217 15202
15218 15203 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15219 15204
15220 15205 fctl_copy_portmap(changelist, pd);
15221 15206 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15222 15207
15223 15208 fctl_release_remote_port(pd);
15224 15209
15225 15210 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15226 15211
15227 15212 return (0);
15228 15213 }
15229 15214
15230 15215 pd->pd_flags = PD_ELS_IN_PROGRESS;
15231 15216 mutex_exit(&pd->pd_mutex);
15232 15217
15233 15218 job->job_counter = 1;
15234 15219
15235 15220 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15236 15221 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15237 15222 if (cmd == NULL) {
15238 15223 fcio->fcio_errno = FC_NOMEM;
15239 15224 fctl_release_remote_port(pd);
15240 15225
15241 15226 mutex_enter(&pd->pd_mutex);
15242 15227 pd->pd_flags = PD_IDLE;
15243 15228 mutex_exit(&pd->pd_mutex);
15244 15229
15245 15230 return (ENOMEM);
15246 15231 }
15247 15232
15248 15233 mutex_enter(&port->fp_mutex);
15249 15234 mutex_enter(&pd->pd_mutex);
15250 15235
15251 15236 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15252 15237 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15253 15238 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15254 15239 cmd->cmd_retry_count = 1;
15255 15240 cmd->cmd_ulp_pkt = NULL;
15256 15241
15257 15242 fp_logo_init(pd, cmd, job);
15258 15243
15259 15244 mutex_exit(&pd->pd_mutex);
15260 15245 mutex_exit(&port->fp_mutex);
15261 15246
15262 15247 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15263 15248 mutex_enter(&pd->pd_mutex);
15264 15249 pd->pd_flags = PD_IDLE;
15265 15250 mutex_exit(&pd->pd_mutex);
15266 15251
15267 15252 fp_free_pkt(cmd);
15268 15253 fctl_release_remote_port(pd);
15269 15254
15270 15255 return (EIO);
15271 15256 }
15272 15257
15273 15258 fp_jobwait(job);
15274 15259
15275 15260 fcio->fcio_errno = job->job_result;
15276 15261 if (job->job_result != FC_SUCCESS) {
15277 15262 mutex_enter(&pd->pd_mutex);
15278 15263 pd->pd_flags = PD_IDLE;
15279 15264 mutex_exit(&pd->pd_mutex);
15280 15265
15281 15266 fctl_release_remote_port(pd);
15282 15267
15283 15268 return (EIO);
15284 15269 }
15285 15270
15286 15271 ASSERT(pd != NULL);
15287 15272
15288 15273 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15289 15274
15290 15275 fctl_copy_portmap(changelist, pd);
15291 15276 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15292 15277 changelist->map_state = PORT_DEVICE_INVALID;
15293 15278
15294 15279 mutex_enter(&port->fp_mutex);
15295 15280 mutex_enter(&pd->pd_mutex);
15296 15281
15297 15282 fctl_delist_did_table(port, pd);
15298 15283 fctl_delist_pwwn_table(port, pd);
15299 15284 pd->pd_flags = PD_IDLE;
15300 15285
15301 15286 mutex_exit(&pd->pd_mutex);
15302 15287 mutex_exit(&port->fp_mutex);
15303 15288
15304 15289 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15305 15290
15306 15291 fctl_release_remote_port(pd);
15307 15292
15308 15293 return (0);
15309 15294 }
15310 15295
15311 15296
15312 15297
15313 15298 /*
15314 15299 * Send a syslog event for adapter port level events.
15315 15300 */
15316 15301 static void
15317 15302 fp_log_port_event(fc_local_port_t *port, char *subclass)
15318 15303 {
15319 15304 nvlist_t *attr_list;
15320 15305
15321 15306 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15322 15307 KM_SLEEP) != DDI_SUCCESS) {
15323 15308 goto alloc_failed;
15324 15309 }
15325 15310
15326 15311 if (nvlist_add_uint32(attr_list, "instance",
15327 15312 port->fp_instance) != DDI_SUCCESS) {
15328 15313 goto error;
15329 15314 }
15330 15315
15331 15316 if (nvlist_add_byte_array(attr_list, "port-wwn",
15332 15317 port->fp_service_params.nport_ww_name.raw_wwn,
15333 15318 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15334 15319 goto error;
15335 15320 }
15336 15321
15337 15322 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15338 15323 subclass, attr_list, NULL, DDI_SLEEP);
15339 15324
15340 15325 nvlist_free(attr_list);
15341 15326 return;
15342 15327
15343 15328 error:
15344 15329 nvlist_free(attr_list);
15345 15330 alloc_failed:
15346 15331 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15347 15332 }
15348 15333
15349 15334
15350 15335 static void
15351 15336 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15352 15337 uint32_t port_id)
15353 15338 {
15354 15339 nvlist_t *attr_list;
15355 15340
15356 15341 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15357 15342 KM_SLEEP) != DDI_SUCCESS) {
15358 15343 goto alloc_failed;
15359 15344 }
15360 15345
15361 15346 if (nvlist_add_uint32(attr_list, "instance",
15362 15347 port->fp_instance) != DDI_SUCCESS) {
15363 15348 goto error;
15364 15349 }
15365 15350
15366 15351 if (nvlist_add_byte_array(attr_list, "port-wwn",
15367 15352 port->fp_service_params.nport_ww_name.raw_wwn,
15368 15353 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15369 15354 goto error;
15370 15355 }
15371 15356
15372 15357 if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15373 15358 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15374 15359 goto error;
15375 15360 }
15376 15361
15377 15362 if (nvlist_add_uint32(attr_list, "target-port-id",
15378 15363 port_id) != DDI_SUCCESS) {
15379 15364 goto error;
15380 15365 }
15381 15366
15382 15367 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15383 15368 subclass, attr_list, NULL, DDI_SLEEP);
15384 15369
15385 15370 nvlist_free(attr_list);
15386 15371 return;
15387 15372
15388 15373 error:
15389 15374 nvlist_free(attr_list);
15390 15375 alloc_failed:
15391 15376 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15392 15377 }
15393 15378
15394 15379 static uint32_t
15395 15380 fp_map_remote_port_state(uint32_t rm_state)
15396 15381 {
15397 15382 switch (rm_state) {
15398 15383 case PORT_DEVICE_LOGGED_IN:
15399 15384 return (FC_HBA_PORTSTATE_ONLINE);
15400 15385 case PORT_DEVICE_VALID:
15401 15386 case PORT_DEVICE_INVALID:
15402 15387 default:
15403 15388 return (FC_HBA_PORTSTATE_UNKNOWN);
15404 15389 }
15405 15390 }
↓ open down ↓ |
8864 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX