Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/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
↓ open down ↓ |
98 lines elided |
↑ open up ↑ |
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 - MODREV_1, /* Rev of the loadable modules system */
110 - &modldrv, /* NULL terminated list of */
111 - NULL /* Linkage structures */
109 + MODREV_1, /* Rev of the loadable modules system */
110 + { &modldrv, NULL } /* NULL terminated list of */
112 111 };
113 112
114 113
115 114
116 115 static uint16_t ns_reg_cmds[] = {
117 116 NS_RPN_ID,
118 117 NS_RNN_ID,
119 118 NS_RCS_ID,
120 119 NS_RFT_ID,
121 120 NS_RPT_ID,
122 121 NS_RSPN_ID,
123 122 NS_RSNN_NN
124 123 };
125 124
126 125 struct fp_xlat {
127 126 uchar_t xlat_state;
128 127 int xlat_rval;
129 128 } fp_xlat [] = {
130 129 { FC_PKT_SUCCESS, FC_SUCCESS },
131 130 { FC_PKT_REMOTE_STOP, FC_FAILURE },
132 131 { FC_PKT_LOCAL_RJT, FC_FAILURE },
133 132 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT },
134 133 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT },
135 134 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY },
136 135 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY },
137 136 { FC_PKT_NPORT_BSY, FC_PBUSY },
138 137 { FC_PKT_FABRIC_BSY, FC_FBUSY },
139 138 { FC_PKT_LS_RJT, FC_FAILURE },
140 139 { FC_PKT_BA_RJT, FC_FAILURE },
141 140 { FC_PKT_TIMEOUT, FC_FAILURE },
142 141 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR },
143 142 { FC_PKT_FAILURE, FC_FAILURE },
144 143 { FC_PKT_PORT_OFFLINE, FC_OFFLINE }
145 144 };
146 145
147 146 static uchar_t fp_valid_alpas[] = {
148 147 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
149 148 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
150 149 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
151 150 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
152 151 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
153 152 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
154 153 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
155 154 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
156 155 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
157 156 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
158 157 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
159 158 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
160 159 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
161 160 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
162 161 };
163 162
164 163 static struct fp_perms {
165 164 uint16_t fp_ioctl_cmd;
166 165 uchar_t fp_open_flag;
167 166 } fp_perm_list [] = {
168 167 { FCIO_GET_NUM_DEVS, FP_OPEN },
169 168 { FCIO_GET_DEV_LIST, FP_OPEN },
170 169 { FCIO_GET_SYM_PNAME, FP_OPEN },
171 170 { FCIO_GET_SYM_NNAME, FP_OPEN },
172 171 { FCIO_SET_SYM_PNAME, FP_EXCL },
173 172 { FCIO_SET_SYM_NNAME, FP_EXCL },
174 173 { FCIO_GET_LOGI_PARAMS, FP_OPEN },
175 174 { FCIO_DEV_LOGIN, FP_EXCL },
176 175 { FCIO_DEV_LOGOUT, FP_EXCL },
177 176 { FCIO_GET_STATE, FP_OPEN },
178 177 { FCIO_DEV_REMOVE, FP_EXCL },
179 178 { FCIO_GET_FCODE_REV, FP_OPEN },
180 179 { FCIO_GET_FW_REV, FP_OPEN },
181 180 { FCIO_GET_DUMP_SIZE, FP_OPEN },
182 181 { FCIO_FORCE_DUMP, FP_EXCL },
183 182 { FCIO_GET_DUMP, FP_OPEN },
184 183 { FCIO_GET_TOPOLOGY, FP_OPEN },
185 184 { FCIO_RESET_LINK, FP_EXCL },
186 185 { FCIO_RESET_HARD, FP_EXCL },
187 186 { FCIO_RESET_HARD_CORE, FP_EXCL },
188 187 { FCIO_DIAG, FP_OPEN },
189 188 { FCIO_NS, FP_EXCL },
190 189 { FCIO_DOWNLOAD_FW, FP_EXCL },
191 190 { FCIO_DOWNLOAD_FCODE, FP_EXCL },
192 191 { FCIO_LINK_STATUS, FP_OPEN },
193 192 { FCIO_GET_HOST_PARAMS, FP_OPEN },
194 193 { FCIO_GET_NODE_ID, FP_OPEN },
195 194 { FCIO_SET_NODE_ID, FP_EXCL },
196 195 { FCIO_SEND_NODE_ID, FP_OPEN },
197 196 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN },
198 197 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN },
199 198 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN },
200 199 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN },
201 200 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN },
202 201 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN },
203 202 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
204 203 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
205 204 { FCIO_DELETE_NPIV_PORT, FP_OPEN },
206 205 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
207 206 { FCIO_CREATE_NPIV_PORT, FP_OPEN },
208 207 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
209 208 };
210 209
211 210 static char *fp_pm_comps[] = {
212 211 "NAME=FC Port",
213 212 "0=Port Down",
214 213 "1=Port Up"
215 214 };
216 215
217 216
218 217 #ifdef _LITTLE_ENDIAN
219 218 #define MAKE_BE_32(x) { \
220 219 uint32_t *ptr1, i; \
221 220 ptr1 = (uint32_t *)(x); \
222 221 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
223 222 *ptr1 = BE_32(*ptr1); \
224 223 ptr1++; \
225 224 } \
226 225 }
227 226 #else
228 227 #define MAKE_BE_32(x)
229 228 #endif
230 229
231 230 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
232 231 static uint32_t fp_options = 0;
233 232
234 233 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
235 234 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */
236 235 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */
237 236 unsigned int fp_offline_ticker; /* seconds */
238 237
239 238 /*
240 239 * Driver global variable to anchor the list of soft state structs for
241 240 * all fp driver instances. Used with the Solaris DDI soft state functions.
242 241 */
243 242 static void *fp_driver_softstate;
244 243
245 244 static clock_t fp_retry_ticks;
246 245 static clock_t fp_offline_ticks;
247 246
248 247 static int fp_retry_ticker;
249 248 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
250 249 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
251 250
252 251 static int fp_log_size = FP_LOG_SIZE;
253 252 static int fp_trace = FP_TRACE_DEFAULT;
254 253 static fc_trace_logq_t *fp_logq = NULL;
255 254
256 255 int fp_get_adapter_paths(char *pathList, int count);
257 256 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
258 257 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
259 258 la_wwn_t tgt_pwwn, uint32_t port_id);
260 259 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
261 260 static void fp_init_symbolic_names(fc_local_port_t *port);
262 261
263 262
264 263 /*
265 264 * Perform global initialization
266 265 */
267 266 int
268 267 _init(void)
269 268 {
270 269 int ret;
271 270
272 271 if ((ret = ddi_soft_state_init(&fp_driver_softstate,
273 272 sizeof (struct fc_local_port), 8)) != 0) {
274 273 return (ret);
275 274 }
276 275
277 276 if ((ret = scsi_hba_init(&modlinkage)) != 0) {
278 277 ddi_soft_state_fini(&fp_driver_softstate);
279 278 return (ret);
280 279 }
281 280
282 281 fp_logq = fc_trace_alloc_logq(fp_log_size);
283 282
284 283 if ((ret = mod_install(&modlinkage)) != 0) {
285 284 fc_trace_free_logq(fp_logq);
286 285 ddi_soft_state_fini(&fp_driver_softstate);
287 286 scsi_hba_fini(&modlinkage);
288 287 }
289 288
290 289 return (ret);
291 290 }
292 291
293 292
294 293 /*
295 294 * Prepare for driver unload
296 295 */
297 296 int
298 297 _fini(void)
299 298 {
300 299 int ret;
301 300
302 301 if ((ret = mod_remove(&modlinkage)) == 0) {
303 302 fc_trace_free_logq(fp_logq);
304 303 ddi_soft_state_fini(&fp_driver_softstate);
305 304 scsi_hba_fini(&modlinkage);
306 305 }
307 306
308 307 return (ret);
309 308 }
310 309
311 310
312 311 /*
313 312 * Request mod_info() to handle all cases
314 313 */
315 314 int
316 315 _info(struct modinfo *modinfo)
317 316 {
318 317 return (mod_info(&modlinkage, modinfo));
319 318 }
320 319
321 320
322 321 /*
323 322 * fp_attach:
324 323 *
325 324 * The respective cmd handlers take care of performing
326 325 * ULP related invocations
327 326 */
328 327 static int
329 328 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
330 329 {
331 330 int rval;
332 331
333 332 /*
334 333 * We check the value of fp_offline_ticker at this
335 334 * point. The variable is global for the driver and
336 335 * not specific to an instance.
337 336 *
338 337 * If there is no user-defined value found in /etc/system
339 338 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
340 339 * The minimum setting for this offline timeout according
341 340 * to the FC-FS2 standard (Fibre Channel Framing and
342 341 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
343 342 *
344 343 * We do not recommend setting the value to less than 10
345 344 * seconds (RA_TOV) or more than 90 seconds. If this
346 345 * variable is greater than 90 seconds then drivers above
347 346 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
348 347 */
349 348
350 349 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
351 350 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
352 351 FP_OFFLINE_TICKER);
353 352
354 353 if ((fp_offline_ticker < 10) ||
355 354 (fp_offline_ticker > 90)) {
356 355 cmn_err(CE_WARN, "Setting fp_offline_ticker to "
357 356 "%d second(s). This is outside the "
358 357 "recommended range of 10..90 seconds",
359 358 fp_offline_ticker);
360 359 }
361 360
362 361 /*
363 362 * Tick every second when there are commands to retry.
364 363 * It should tick at the least granular value of pkt_timeout
365 364 * (which is one second)
366 365 */
367 366 fp_retry_ticker = 1;
368 367
369 368 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
370 369 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
371 370
372 371 switch (cmd) {
373 372 case DDI_ATTACH:
374 373 rval = fp_attach_handler(dip);
375 374 break;
376 375
377 376 case DDI_RESUME:
378 377 rval = fp_resume_handler(dip);
379 378 break;
380 379
381 380 default:
382 381 rval = DDI_FAILURE;
383 382 break;
384 383 }
385 384 return (rval);
386 385 }
387 386
388 387
389 388 /*
390 389 * fp_detach:
391 390 *
392 391 * If a ULP fails to handle cmd request converse of
393 392 * cmd is invoked for ULPs that previously succeeded
394 393 * cmd request.
395 394 */
396 395 static int
397 396 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
398 397 {
399 398 int rval = DDI_FAILURE;
400 399 fc_local_port_t *port;
401 400 fc_attach_cmd_t converse;
402 401 uint8_t cnt;
403 402
404 403 if ((port = ddi_get_soft_state(fp_driver_softstate,
405 404 ddi_get_instance(dip))) == NULL) {
406 405 return (DDI_FAILURE);
407 406 }
408 407
409 408 mutex_enter(&port->fp_mutex);
410 409
411 410 if (port->fp_ulp_attach) {
412 411 mutex_exit(&port->fp_mutex);
413 412 return (DDI_FAILURE);
414 413 }
415 414
416 415 switch (cmd) {
417 416 case DDI_DETACH:
418 417 if (port->fp_task != FP_TASK_IDLE) {
419 418 mutex_exit(&port->fp_mutex);
420 419 return (DDI_FAILURE);
421 420 }
422 421
423 422 /* Let's attempt to quit the job handler gracefully */
424 423 port->fp_soft_state |= FP_DETACH_INPROGRESS;
425 424
426 425 mutex_exit(&port->fp_mutex);
427 426 converse = FC_CMD_ATTACH;
428 427 if (fctl_detach_ulps(port, FC_CMD_DETACH,
429 428 &modlinkage) != FC_SUCCESS) {
430 429 mutex_enter(&port->fp_mutex);
431 430 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
432 431 mutex_exit(&port->fp_mutex);
433 432 rval = DDI_FAILURE;
434 433 break;
435 434 }
436 435
437 436 mutex_enter(&port->fp_mutex);
438 437 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
439 438 cnt++) {
440 439 mutex_exit(&port->fp_mutex);
441 440 delay(drv_usectohz(1000000));
442 441 mutex_enter(&port->fp_mutex);
443 442 }
444 443
445 444 if (port->fp_job_head) {
446 445 mutex_exit(&port->fp_mutex);
447 446 rval = DDI_FAILURE;
448 447 break;
449 448 }
450 449 mutex_exit(&port->fp_mutex);
451 450
452 451 rval = fp_detach_handler(port);
453 452 break;
454 453
455 454 case DDI_SUSPEND:
456 455 mutex_exit(&port->fp_mutex);
457 456 converse = FC_CMD_RESUME;
458 457 if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
459 458 &modlinkage) != FC_SUCCESS) {
460 459 rval = DDI_FAILURE;
461 460 break;
462 461 }
463 462 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
464 463 (void) callb_generic_cpr(&port->fp_cpr_info,
465 464 CB_CODE_CPR_RESUME);
466 465 }
467 466 break;
468 467
469 468 default:
470 469 mutex_exit(&port->fp_mutex);
471 470 break;
472 471 }
473 472
474 473 /*
475 474 * Use softint to perform reattach. Mark fp_ulp_attach so we
476 475 * don't attempt to do this repeatedly on behalf of some persistent
477 476 * caller.
478 477 */
479 478 if (rval != DDI_SUCCESS) {
480 479 mutex_enter(&port->fp_mutex);
481 480 port->fp_ulp_attach = 1;
482 481
483 482 /*
484 483 * If the port is in the low power mode then there is
485 484 * possibility that fca too could be in low power mode.
486 485 * Try to raise the power before calling attach ulps.
487 486 */
488 487
489 488 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
490 489 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
491 490 mutex_exit(&port->fp_mutex);
492 491 (void) pm_raise_power(port->fp_port_dip,
493 492 FP_PM_COMPONENT, FP_PM_PORT_UP);
494 493 } else {
495 494 mutex_exit(&port->fp_mutex);
496 495 }
497 496
498 497
499 498 fp_attach_ulps(port, converse);
500 499
501 500 mutex_enter(&port->fp_mutex);
502 501 while (port->fp_ulp_attach) {
503 502 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
504 503 }
505 504
506 505 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
507 506
508 507 /*
509 508 * Mark state as detach failed so asynchronous ULP attach
510 509 * events (downstream, not the ones we're initiating with
511 510 * the call to fp_attach_ulps) are not honored. We're
512 511 * really still in pending detach.
513 512 */
514 513 port->fp_soft_state |= FP_DETACH_FAILED;
515 514
516 515 mutex_exit(&port->fp_mutex);
517 516 }
518 517
519 518 return (rval);
520 519 }
521 520
522 521
523 522 /*
524 523 * fp_getinfo:
525 524 * Given the device number, return either the
526 525 * dev_info_t pointer or the instance number.
527 526 */
528 527
529 528 /* ARGSUSED */
530 529 static int
531 530 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
532 531 {
533 532 int rval;
534 533 minor_t instance;
535 534 fc_local_port_t *port;
536 535
537 536 rval = DDI_SUCCESS;
538 537 instance = getminor((dev_t)arg);
539 538
540 539 switch (cmd) {
541 540 case DDI_INFO_DEVT2DEVINFO:
542 541 if ((port = ddi_get_soft_state(fp_driver_softstate,
543 542 instance)) == NULL) {
544 543 rval = DDI_FAILURE;
545 544 break;
546 545 }
547 546 *result = (void *)port->fp_port_dip;
548 547 break;
549 548
550 549 case DDI_INFO_DEVT2INSTANCE:
551 550 *result = (void *)(uintptr_t)instance;
552 551 break;
553 552
554 553 default:
555 554 rval = DDI_FAILURE;
556 555 break;
557 556 }
558 557
559 558 return (rval);
560 559 }
561 560
562 561
563 562 /*
564 563 * Entry point for power up and power down request from kernel
565 564 */
566 565 static int
567 566 fp_power(dev_info_t *dip, int comp, int level)
568 567 {
569 568 int rval = DDI_FAILURE;
570 569 fc_local_port_t *port;
571 570
572 571 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
573 572 if (port == NULL || comp != FP_PM_COMPONENT) {
574 573 return (rval);
575 574 }
576 575
577 576 switch (level) {
578 577 case FP_PM_PORT_UP:
579 578 rval = DDI_SUCCESS;
580 579
581 580 /*
582 581 * If the port is DDI_SUSPENDed, let the DDI_RESUME
583 582 * code complete the rediscovery.
584 583 */
585 584 mutex_enter(&port->fp_mutex);
586 585 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
587 586 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
588 587 port->fp_pm_level = FP_PM_PORT_UP;
589 588 mutex_exit(&port->fp_mutex);
590 589 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
591 590 break;
592 591 }
593 592
594 593 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
595 594 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
596 595
597 596 port->fp_pm_level = FP_PM_PORT_UP;
598 597 rval = fp_power_up(port);
599 598 if (rval != DDI_SUCCESS) {
600 599 port->fp_pm_level = FP_PM_PORT_DOWN;
601 600 }
602 601 } else {
603 602 port->fp_pm_level = FP_PM_PORT_UP;
604 603 }
605 604 mutex_exit(&port->fp_mutex);
606 605 break;
607 606
608 607 case FP_PM_PORT_DOWN:
609 608 mutex_enter(&port->fp_mutex);
610 609
611 610 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
612 611 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
613 612 /*
614 613 * PM framework goofed up. We have don't
615 614 * have any PM components. Let's never go down.
616 615 */
617 616 mutex_exit(&port->fp_mutex);
618 617 break;
619 618
620 619 }
621 620
622 621 if (port->fp_ulp_attach) {
623 622 /* We shouldn't let the power go down */
624 623 mutex_exit(&port->fp_mutex);
625 624 break;
626 625 }
627 626
628 627 /*
629 628 * Not a whole lot to do if we are detaching
630 629 */
631 630 if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
632 631 port->fp_pm_level = FP_PM_PORT_DOWN;
633 632 mutex_exit(&port->fp_mutex);
634 633 rval = DDI_SUCCESS;
635 634 break;
636 635 }
637 636
638 637 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
639 638 port->fp_pm_level = FP_PM_PORT_DOWN;
640 639
641 640 rval = fp_power_down(port);
642 641 if (rval != DDI_SUCCESS) {
643 642 port->fp_pm_level = FP_PM_PORT_UP;
644 643 ASSERT(!(port->fp_soft_state &
645 644 FP_SOFT_POWER_DOWN));
646 645 } else {
647 646 ASSERT(port->fp_soft_state &
648 647 FP_SOFT_POWER_DOWN);
649 648 }
650 649 }
651 650 mutex_exit(&port->fp_mutex);
652 651 break;
653 652
654 653 default:
655 654 break;
656 655 }
657 656
658 657 return (rval);
659 658 }
660 659
661 660
662 661 /*
663 662 * Open FC port devctl node
664 663 */
665 664 static int
666 665 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
667 666 {
668 667 int instance;
669 668 fc_local_port_t *port;
670 669
671 670 if (otype != OTYP_CHR) {
672 671 return (EINVAL);
673 672 }
674 673
675 674 /*
676 675 * This is not a toy to play with. Allow only powerful
677 676 * users (hopefully knowledgeable) to access the port
678 677 * (A hacker potentially could download a sick binary
679 678 * file into FCA)
680 679 */
681 680 if (drv_priv(credp)) {
682 681 return (EPERM);
683 682 }
684 683
685 684 instance = (int)getminor(*devp);
686 685
687 686 port = ddi_get_soft_state(fp_driver_softstate, instance);
688 687 if (port == NULL) {
689 688 return (ENXIO);
690 689 }
691 690
692 691 mutex_enter(&port->fp_mutex);
693 692 if (port->fp_flag & FP_EXCL) {
694 693 /*
695 694 * It is already open for exclusive access.
696 695 * So shut the door on this caller.
697 696 */
698 697 mutex_exit(&port->fp_mutex);
699 698 return (EBUSY);
700 699 }
701 700
702 701 if (flag & FEXCL) {
703 702 if (port->fp_flag & FP_OPEN) {
704 703 /*
705 704 * Exclusive operation not possible
706 705 * as it is already opened
707 706 */
708 707 mutex_exit(&port->fp_mutex);
709 708 return (EBUSY);
710 709 }
711 710 port->fp_flag |= FP_EXCL;
712 711 }
713 712 port->fp_flag |= FP_OPEN;
714 713 mutex_exit(&port->fp_mutex);
715 714
716 715 return (0);
717 716 }
718 717
719 718
720 719 /*
721 720 * The driver close entry point is called on the last close()
722 721 * of a device. So it is perfectly alright to just clobber the
723 722 * open flag and reset it to idle (instead of having to reset
724 723 * each flag bits). For any confusion, check out close(9E).
725 724 */
726 725
727 726 /* ARGSUSED */
728 727 static int
729 728 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
730 729 {
731 730 int instance;
732 731 fc_local_port_t *port;
733 732
734 733 if (otype != OTYP_CHR) {
735 734 return (EINVAL);
736 735 }
737 736
738 737 instance = (int)getminor(dev);
739 738
740 739 port = ddi_get_soft_state(fp_driver_softstate, instance);
741 740 if (port == NULL) {
742 741 return (ENXIO);
743 742 }
744 743
745 744 mutex_enter(&port->fp_mutex);
746 745 if ((port->fp_flag & FP_OPEN) == 0) {
747 746 mutex_exit(&port->fp_mutex);
748 747 return (ENODEV);
749 748 }
750 749 port->fp_flag = FP_IDLE;
751 750 mutex_exit(&port->fp_mutex);
752 751
753 752 return (0);
754 753 }
755 754
756 755 /*
757 756 * Handle IOCTL requests
758 757 */
759 758
760 759 /* ARGSUSED */
761 760 static int
762 761 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
763 762 {
764 763 int instance;
765 764 int ret = 0;
766 765 fcio_t fcio;
767 766 fc_local_port_t *port;
768 767
769 768 instance = (int)getminor(dev);
770 769
771 770 port = ddi_get_soft_state(fp_driver_softstate, instance);
772 771 if (port == NULL) {
773 772 return (ENXIO);
774 773 }
775 774
776 775 mutex_enter(&port->fp_mutex);
777 776 if ((port->fp_flag & FP_OPEN) == 0) {
778 777 mutex_exit(&port->fp_mutex);
779 778 return (ENXIO);
780 779 }
781 780
782 781 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
783 782 mutex_exit(&port->fp_mutex);
784 783 return (ENXIO);
785 784 }
786 785
787 786 mutex_exit(&port->fp_mutex);
788 787
789 788 /* this will raise power if necessary */
790 789 ret = fctl_busy_port(port);
791 790 if (ret != 0) {
792 791 return (ret);
793 792 }
794 793
795 794 ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
796 795
797 796
798 797 switch (cmd) {
799 798 case FCIO_CMD: {
800 799 #ifdef _MULTI_DATAMODEL
801 800 switch (ddi_model_convert_from(mode & FMODELS)) {
802 801 case DDI_MODEL_ILP32: {
803 802 struct fcio32 fcio32;
804 803
805 804 if (ddi_copyin((void *)data, (void *)&fcio32,
806 805 sizeof (struct fcio32), mode)) {
807 806 ret = EFAULT;
808 807 break;
809 808 }
810 809 fcio.fcio_xfer = fcio32.fcio_xfer;
811 810 fcio.fcio_cmd = fcio32.fcio_cmd;
812 811 fcio.fcio_flags = fcio32.fcio_flags;
813 812 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
814 813 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
815 814 fcio.fcio_ibuf =
816 815 (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
817 816 fcio.fcio_olen = (size_t)fcio32.fcio_olen;
818 817 fcio.fcio_obuf =
819 818 (caddr_t)(uintptr_t)fcio32.fcio_obuf;
820 819 fcio.fcio_alen = (size_t)fcio32.fcio_alen;
821 820 fcio.fcio_abuf =
822 821 (caddr_t)(uintptr_t)fcio32.fcio_abuf;
823 822 fcio.fcio_errno = fcio32.fcio_errno;
824 823 break;
825 824 }
826 825
827 826 case DDI_MODEL_NONE:
828 827 if (ddi_copyin((void *)data, (void *)&fcio,
829 828 sizeof (fcio_t), mode)) {
830 829 ret = EFAULT;
831 830 }
832 831 break;
833 832 }
834 833 #else /* _MULTI_DATAMODEL */
835 834 if (ddi_copyin((void *)data, (void *)&fcio,
836 835 sizeof (fcio_t), mode)) {
837 836 ret = EFAULT;
838 837 break;
839 838 }
840 839 #endif /* _MULTI_DATAMODEL */
841 840 if (!ret) {
842 841 ret = fp_fciocmd(port, data, mode, &fcio);
843 842 }
844 843 break;
845 844 }
846 845
847 846 default:
848 847 ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
849 848 mode, credp, rval);
850 849 }
851 850
852 851 fctl_idle_port(port);
853 852
854 853 return (ret);
855 854 }
856 855
857 856
858 857 /*
859 858 * Init Symbolic Port Name and Node Name
860 859 * LV will try to get symbolic names from FCA driver
861 860 * and register these to name server,
862 861 * if LV fails to get these,
863 862 * LV will register its default symbolic names to name server.
864 863 * The Default symbolic node name format is :
865 864 * <hostname>:<hba driver name>(instance)
866 865 * The Default symbolic port name format is :
867 866 * <fp path name>
868 867 */
869 868 static void
870 869 fp_init_symbolic_names(fc_local_port_t *port)
871 870 {
872 871 const char *vendorname = ddi_driver_name(port->fp_fca_dip);
873 872 char *sym_name;
874 873 char fcaname[50] = {0};
875 874 int hostnlen, fcanlen;
876 875
877 876 if (port->fp_sym_node_namelen == 0) {
878 877 hostnlen = strlen(utsname.nodename);
879 878 (void) snprintf(fcaname, sizeof (fcaname),
880 879 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
881 880 fcanlen = strlen(fcaname);
882 881
883 882 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
884 883 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
885 884 port->fp_sym_node_namelen = strlen(sym_name);
886 885 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
887 886 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
888 887 }
889 888 (void) strncpy(port->fp_sym_node_name, sym_name,
890 889 port->fp_sym_node_namelen);
891 890 kmem_free(sym_name, hostnlen + fcanlen + 2);
892 891 }
893 892
894 893 if (port->fp_sym_port_namelen == 0) {
895 894 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
896 895
897 896 (void) ddi_pathname(port->fp_port_dip, pathname);
898 897 port->fp_sym_port_namelen = strlen(pathname);
899 898 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
900 899 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
901 900 }
902 901 (void) strncpy(port->fp_sym_port_name, pathname,
903 902 port->fp_sym_port_namelen);
904 903 kmem_free(pathname, MAXPATHLEN);
905 904 }
906 905 }
907 906
908 907
909 908 /*
910 909 * Perform port attach
911 910 */
912 911 static int
913 912 fp_attach_handler(dev_info_t *dip)
914 913 {
915 914 int rval;
916 915 int instance;
917 916 int port_num;
918 917 int port_len;
919 918 char name[30];
920 919 char i_pwwn[17];
921 920 fp_cmd_t *pkt;
922 921 uint32_t ub_count;
923 922 fc_local_port_t *port;
924 923 job_request_t *job;
925 924 fc_local_port_t *phyport = NULL;
926 925 int portpro1;
927 926 char pwwn[17], nwwn[17];
928 927
929 928 instance = ddi_get_instance(dip);
930 929 port_len = sizeof (port_num);
931 930 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
932 931 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
933 932 (caddr_t)&port_num, &port_len);
934 933 if (rval != DDI_SUCCESS) {
935 934 cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
936 935 instance);
937 936 return (DDI_FAILURE);
938 937 }
939 938
940 939 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
941 940 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
942 941 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
943 942 instance);
944 943 return (DDI_FAILURE);
945 944 }
946 945
947 946 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
948 947 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
949 948 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
950 949 " point minor node", instance);
951 950 ddi_remove_minor_node(dip, NULL);
952 951 return (DDI_FAILURE);
953 952 }
954 953
955 954 if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
956 955 != DDI_SUCCESS) {
957 956 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
958 957 instance);
959 958 ddi_remove_minor_node(dip, NULL);
960 959 return (DDI_FAILURE);
961 960 }
962 961 port = ddi_get_soft_state(fp_driver_softstate, instance);
963 962
964 963 (void) sprintf(port->fp_ibuf, "fp(%d)", instance);
965 964
966 965 port->fp_instance = instance;
967 966 port->fp_ulp_attach = 1;
968 967 port->fp_port_num = port_num;
969 968 port->fp_verbose = fp_verbosity;
970 969 port->fp_options = fp_options;
971 970
972 971 port->fp_fca_dip = ddi_get_parent(dip);
973 972 port->fp_port_dip = dip;
974 973 port->fp_fca_tran = (fc_fca_tran_t *)
975 974 ddi_get_driver_private(port->fp_fca_dip);
976 975
977 976 port->fp_task = port->fp_last_task = FP_TASK_IDLE;
978 977
979 978 /*
980 979 * Init the starting value of fp_rscn_count. Note that if
981 980 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
982 981 * actual # of RSCNs will be (fp_rscn_count - 1)
983 982 */
984 983 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
985 984
986 985 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
987 986 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
988 987 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
989 988
990 989 (void) sprintf(name, "fp%d_cache", instance);
991 990
992 991 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
993 992 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
994 993 "phyport-instance", -1)) != -1) {
995 994 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
996 995 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
997 996 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
998 997 port->fp_npiv_type = FC_NPIV_PORT;
999 998 }
1000 999
1001 1000 /*
1002 1001 * Allocate the pool of fc_packet_t structs to be used with
1003 1002 * this fp instance.
1004 1003 */
1005 1004 port->fp_pkt_cache = kmem_cache_create(name,
1006 1005 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1007 1006 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1008 1007 NULL, 0);
1009 1008 port->fp_out_fpcmds = 0;
1010 1009 if (port->fp_pkt_cache == NULL) {
1011 1010 goto cache_alloc_failed;
1012 1011 }
1013 1012
1014 1013
1015 1014 /*
1016 1015 * Allocate the d_id and pwwn hash tables for all remote ports
1017 1016 * connected to this local port.
1018 1017 */
1019 1018 port->fp_did_table = kmem_zalloc(did_table_size *
1020 1019 sizeof (struct d_id_hash), KM_SLEEP);
1021 1020
1022 1021 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1023 1022 sizeof (struct pwwn_hash), KM_SLEEP);
1024 1023
1025 1024 port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1026 1025 MINCLSYSPRI, 1, 16, 0);
1027 1026
1028 1027 /* Indicate that don't have the pm components yet */
1029 1028 port->fp_soft_state |= FP_SOFT_NO_PMCOMP;
1030 1029
1031 1030 /*
1032 1031 * Bind the callbacks with the FCA driver. This will open the gate
1033 1032 * for asynchronous callbacks, so after this call the fp_mutex
1034 1033 * must be held when updating the fc_local_port_t struct.
1035 1034 *
1036 1035 * This is done _before_ setting up the job thread so we can avoid
1037 1036 * cleaning up after the thread_create() in the error path. This
1038 1037 * also means fp will be operating with fp_els_resp_pkt set to NULL.
1039 1038 */
1040 1039 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1041 1040 goto bind_callbacks_failed;
1042 1041 }
1043 1042
1044 1043 if (phyport) {
1045 1044 mutex_enter(&phyport->fp_mutex);
1046 1045 if (phyport->fp_port_next) {
1047 1046 phyport->fp_port_next->fp_port_prev = port;
1048 1047 port->fp_port_next = phyport->fp_port_next;
1049 1048 phyport->fp_port_next = port;
1050 1049 port->fp_port_prev = phyport;
1051 1050 } else {
1052 1051 phyport->fp_port_next = port;
1053 1052 phyport->fp_port_prev = port;
1054 1053 port->fp_port_next = phyport;
1055 1054 port->fp_port_prev = phyport;
1056 1055 }
1057 1056 mutex_exit(&phyport->fp_mutex);
1058 1057 }
1059 1058
1060 1059 /*
1061 1060 * Init Symbolic Names
1062 1061 */
1063 1062 fp_init_symbolic_names(port);
1064 1063
1065 1064 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1066 1065 KM_SLEEP, NULL);
1067 1066
1068 1067 if (pkt == NULL) {
1069 1068 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1070 1069 instance);
1071 1070 goto alloc_els_packet_failed;
1072 1071 }
1073 1072
1074 1073 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1075 1074 v.v_maxsyspri - 2);
1076 1075
1077 1076 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1078 1077 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1079 1078 i_pwwn) != DDI_PROP_SUCCESS) {
1080 1079 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1081 1080 "fp(%d): Updating 'initiator-port' property"
1082 1081 " on fp dev_info node failed", instance);
1083 1082 }
1084 1083
1085 1084 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1086 1085 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1087 1086 i_pwwn) != DDI_PROP_SUCCESS) {
1088 1087 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1089 1088 "fp(%d): Updating 'initiator-node' property"
1090 1089 " on fp dev_info node failed", instance);
1091 1090 }
1092 1091
1093 1092 mutex_enter(&port->fp_mutex);
1094 1093 port->fp_els_resp_pkt = pkt;
1095 1094 mutex_exit(&port->fp_mutex);
1096 1095
1097 1096 /*
1098 1097 * Determine the count of unsolicited buffers this FCA can support
1099 1098 */
1100 1099 fp_retrieve_caps(port);
1101 1100
1102 1101 /*
1103 1102 * Allocate unsolicited buffer tokens
1104 1103 */
1105 1104 if (port->fp_ub_count) {
1106 1105 ub_count = port->fp_ub_count;
1107 1106 port->fp_ub_tokens = kmem_zalloc(ub_count *
1108 1107 sizeof (*port->fp_ub_tokens), KM_SLEEP);
1109 1108 /*
1110 1109 * Do not fail the attach if unsolicited buffer allocation
1111 1110 * fails; Just try to get along with whatever the FCA can do.
1112 1111 */
1113 1112 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1114 1113 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1115 1114 FC_SUCCESS || ub_count != port->fp_ub_count) {
1116 1115 cmn_err(CE_WARN, "fp(%d): failed to allocate "
1117 1116 " Unsolicited buffers. proceeding with attach...",
1118 1117 instance);
1119 1118 kmem_free(port->fp_ub_tokens,
1120 1119 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1121 1120 port->fp_ub_tokens = NULL;
1122 1121 }
1123 1122 }
1124 1123
1125 1124 fp_load_ulp_modules(dip, port);
1126 1125
1127 1126 /*
1128 1127 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1129 1128 */
1130 1129 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1131 1130 "pm-hardware-state", "needs-suspend-resume",
1132 1131 strlen("needs-suspend-resume") + 1);
1133 1132
1134 1133 /*
1135 1134 * fctl maintains a list of all port handles, so
1136 1135 * help fctl add this one to its list now.
1137 1136 */
1138 1137 mutex_enter(&port->fp_mutex);
1139 1138 fctl_add_port(port);
1140 1139
1141 1140 /*
1142 1141 * If a state change is already in progress, set the bind state t
1143 1142 * OFFLINE as well, so further state change callbacks into ULPs
1144 1143 * will pass the appropriate states
1145 1144 */
1146 1145 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1147 1146 port->fp_statec_busy) {
1148 1147 port->fp_bind_state = FC_STATE_OFFLINE;
1149 1148 mutex_exit(&port->fp_mutex);
1150 1149
1151 1150 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1152 1151 } else {
1153 1152 /*
1154 1153 * Without dropping the mutex, ensure that the port
1155 1154 * startup happens ahead of state change callback
1156 1155 * processing
1157 1156 */
1158 1157 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1159 1158
1160 1159 port->fp_last_task = port->fp_task;
1161 1160 port->fp_task = FP_TASK_PORT_STARTUP;
1162 1161
1163 1162 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1164 1163 fp_startup_done, (opaque_t)port, KM_SLEEP);
1165 1164
1166 1165 port->fp_job_head = port->fp_job_tail = job;
1167 1166
1168 1167 cv_signal(&port->fp_cv);
1169 1168
1170 1169 mutex_exit(&port->fp_mutex);
1171 1170 }
1172 1171
1173 1172 mutex_enter(&port->fp_mutex);
1174 1173 while (port->fp_ulp_attach) {
1175 1174 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1176 1175 }
1177 1176 mutex_exit(&port->fp_mutex);
1178 1177
1179 1178 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1180 1179 "pm-components", fp_pm_comps,
1181 1180 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1182 1181 DDI_PROP_SUCCESS) {
1183 1182 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1184 1183 " components property, PM disabled on this port.");
1185 1184 mutex_enter(&port->fp_mutex);
1186 1185 port->fp_pm_level = FP_PM_PORT_UP;
1187 1186 mutex_exit(&port->fp_mutex);
1188 1187 } else {
1189 1188 if (pm_raise_power(dip, FP_PM_COMPONENT,
1190 1189 FP_PM_PORT_UP) != DDI_SUCCESS) {
1191 1190 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1192 1191 " power level");
1193 1192 mutex_enter(&port->fp_mutex);
1194 1193 port->fp_pm_level = FP_PM_PORT_UP;
1195 1194 mutex_exit(&port->fp_mutex);
1196 1195 }
1197 1196
1198 1197 /*
1199 1198 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1200 1199 * the call to pm_raise_power. The PM framework can't
1201 1200 * handle multiple threads calling into it during attach.
1202 1201 */
1203 1202
1204 1203 mutex_enter(&port->fp_mutex);
1205 1204 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP;
1206 1205 mutex_exit(&port->fp_mutex);
1207 1206 }
1208 1207
1209 1208 ddi_report_dev(dip);
1210 1209
1211 1210 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1212 1211
1213 1212 return (DDI_SUCCESS);
1214 1213
1215 1214 /*
1216 1215 * Unwind any/all preceeding allocations in the event of an error.
1217 1216 */
1218 1217
1219 1218 alloc_els_packet_failed:
1220 1219
1221 1220 if (port->fp_fca_handle != NULL) {
1222 1221 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1223 1222 port->fp_fca_handle = NULL;
1224 1223 }
1225 1224
1226 1225 if (port->fp_ub_tokens != NULL) {
1227 1226 (void) fc_ulp_ubfree(port, port->fp_ub_count,
1228 1227 port->fp_ub_tokens);
1229 1228 kmem_free(port->fp_ub_tokens,
1230 1229 port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1231 1230 port->fp_ub_tokens = NULL;
1232 1231 }
1233 1232
1234 1233 if (port->fp_els_resp_pkt != NULL) {
1235 1234 fp_free_pkt(port->fp_els_resp_pkt);
1236 1235 port->fp_els_resp_pkt = NULL;
1237 1236 }
1238 1237
1239 1238 bind_callbacks_failed:
1240 1239
1241 1240 if (port->fp_taskq != NULL) {
1242 1241 taskq_destroy(port->fp_taskq);
1243 1242 }
1244 1243
1245 1244 if (port->fp_pwwn_table != NULL) {
1246 1245 kmem_free(port->fp_pwwn_table,
1247 1246 pwwn_table_size * sizeof (struct pwwn_hash));
1248 1247 port->fp_pwwn_table = NULL;
1249 1248 }
1250 1249
1251 1250 if (port->fp_did_table != NULL) {
1252 1251 kmem_free(port->fp_did_table,
1253 1252 did_table_size * sizeof (struct d_id_hash));
1254 1253 port->fp_did_table = NULL;
1255 1254 }
1256 1255
1257 1256 if (port->fp_pkt_cache != NULL) {
1258 1257 kmem_cache_destroy(port->fp_pkt_cache);
1259 1258 port->fp_pkt_cache = NULL;
1260 1259 }
1261 1260
1262 1261 cache_alloc_failed:
1263 1262
1264 1263 cv_destroy(&port->fp_attach_cv);
1265 1264 cv_destroy(&port->fp_cv);
1266 1265 mutex_destroy(&port->fp_mutex);
1267 1266 ddi_remove_minor_node(port->fp_port_dip, NULL);
1268 1267 ddi_soft_state_free(fp_driver_softstate, instance);
1269 1268 ddi_prop_remove_all(dip);
1270 1269
1271 1270 return (DDI_FAILURE);
1272 1271 }
1273 1272
1274 1273
1275 1274 /*
1276 1275 * Handle DDI_RESUME request
1277 1276 */
1278 1277 static int
1279 1278 fp_resume_handler(dev_info_t *dip)
1280 1279 {
1281 1280 int rval;
1282 1281 fc_local_port_t *port;
1283 1282
1284 1283 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1285 1284
1286 1285 ASSERT(port != NULL);
1287 1286
1288 1287 #ifdef DEBUG
1289 1288 mutex_enter(&port->fp_mutex);
1290 1289 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1291 1290 mutex_exit(&port->fp_mutex);
1292 1291 #endif
1293 1292
1294 1293 /*
1295 1294 * If the port was power suspended, raise the power level
1296 1295 */
1297 1296 mutex_enter(&port->fp_mutex);
1298 1297 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1299 1298 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1300 1299 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1301 1300
1302 1301 mutex_exit(&port->fp_mutex);
1303 1302 if (pm_raise_power(dip, FP_PM_COMPONENT,
1304 1303 FP_PM_PORT_UP) != DDI_SUCCESS) {
1305 1304 FP_TRACE(FP_NHEAD2(9, 0),
1306 1305 "Failed to raise the power level");
1307 1306 return (DDI_FAILURE);
1308 1307 }
1309 1308 mutex_enter(&port->fp_mutex);
1310 1309 }
1311 1310 port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1312 1311 mutex_exit(&port->fp_mutex);
1313 1312
1314 1313 /*
1315 1314 * All the discovery is initiated and handled by per-port thread.
1316 1315 * Further all the discovery is done in handled in callback mode
1317 1316 * (not polled mode); In a specific case such as this, the discovery
1318 1317 * is required to happen in polled mode. The easiest way out is
1319 1318 * to bail out port thread and get started. Come back and fix this
1320 1319 * to do on demand discovery initiated by ULPs. ULPs such as FCP
1321 1320 * will do on-demand discovery during pre-power-up busctl handling
1322 1321 * which will only be possible when SCSA provides a new HBA vector
1323 1322 * for sending down the PM busctl requests.
1324 1323 */
1325 1324 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1326 1325
1327 1326 rval = fp_resume_all(port, FC_CMD_RESUME);
1328 1327 if (rval != DDI_SUCCESS) {
1329 1328 mutex_enter(&port->fp_mutex);
1330 1329 port->fp_soft_state |= FP_SOFT_SUSPEND;
1331 1330 mutex_exit(&port->fp_mutex);
1332 1331 (void) callb_generic_cpr(&port->fp_cpr_info,
1333 1332 CB_CODE_CPR_CHKPT);
1334 1333 }
1335 1334
1336 1335 return (rval);
1337 1336 }
1338 1337
1339 1338 /*
1340 1339 * Perform FC Port power on initialization
1341 1340 */
1342 1341 static int
1343 1342 fp_power_up(fc_local_port_t *port)
1344 1343 {
1345 1344 int rval;
1346 1345
1347 1346 ASSERT(MUTEX_HELD(&port->fp_mutex));
1348 1347
1349 1348 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1350 1349 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1351 1350
1352 1351 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1353 1352
1354 1353 mutex_exit(&port->fp_mutex);
1355 1354
1356 1355 rval = fp_resume_all(port, FC_CMD_POWER_UP);
1357 1356 if (rval != DDI_SUCCESS) {
1358 1357 mutex_enter(&port->fp_mutex);
1359 1358 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1360 1359 } else {
1361 1360 mutex_enter(&port->fp_mutex);
1362 1361 }
1363 1362
1364 1363 return (rval);
1365 1364 }
1366 1365
1367 1366
1368 1367 /*
1369 1368 * It is important to note that the power may possibly be removed between
1370 1369 * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1371 1370 * FC port hardware would have gone through an OFFLINE to ONLINE transition
1372 1371 * (hardware state). In this case, the port driver may need to rediscover the
1373 1372 * topology, perform LOGINs, register with the name server again and perform
1374 1373 * any such port initialization procedures. To perform LOGINs, the driver could
1375 1374 * use the port device handle to see if a LOGIN needs to be performed and use
1376 1375 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1377 1376 * or removed) which will be reflected in the map the ULPs will see.
1378 1377 */
1379 1378 static int
1380 1379 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1381 1380 {
1382 1381
1383 1382 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1384 1383
1385 1384 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1386 1385 return (DDI_FAILURE);
1387 1386 }
1388 1387
1389 1388 mutex_enter(&port->fp_mutex);
1390 1389
1391 1390 /*
1392 1391 * If there are commands queued for delayed retry, instead of
1393 1392 * working the hard way to figure out which ones are good for
1394 1393 * restart and which ones not (ELSs are definitely not good
1395 1394 * as the port will have to go through a new spin of rediscovery
1396 1395 * now), so just flush them out.
1397 1396 */
1398 1397 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1399 1398 fp_cmd_t *cmd;
1400 1399
1401 1400 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1402 1401
1403 1402 mutex_exit(&port->fp_mutex);
1404 1403 while ((cmd = fp_deque_cmd(port)) != NULL) {
1405 1404 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1406 1405 fp_iodone(cmd);
1407 1406 }
1408 1407 mutex_enter(&port->fp_mutex);
1409 1408 }
1410 1409
1411 1410 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1412 1411 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1413 1412 port->fp_dev_count) {
1414 1413 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1415 1414 port->fp_offline_tid = timeout(fp_offline_timeout,
1416 1415 (caddr_t)port, fp_offline_ticks);
1417 1416 }
1418 1417 if (port->fp_job_head) {
1419 1418 cv_signal(&port->fp_cv);
1420 1419 }
1421 1420 mutex_exit(&port->fp_mutex);
1422 1421 fctl_attach_ulps(port, cmd, &modlinkage);
1423 1422 } else {
1424 1423 struct job_request *job;
1425 1424
1426 1425 /*
1427 1426 * If an OFFLINE timer was running at the time of
1428 1427 * suspending, there is no need to restart it as
1429 1428 * the port is ONLINE now.
1430 1429 */
1431 1430 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1432 1431 if (port->fp_statec_busy == 0) {
1433 1432 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1434 1433 }
1435 1434 port->fp_statec_busy++;
1436 1435 mutex_exit(&port->fp_mutex);
1437 1436
1438 1437 job = fctl_alloc_job(JOB_PORT_ONLINE,
1439 1438 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1440 1439 fctl_enque_job(port, job);
1441 1440
1442 1441 fctl_jobwait(job);
1443 1442 fctl_remove_oldies(port);
1444 1443
1445 1444 fctl_attach_ulps(port, cmd, &modlinkage);
1446 1445 fctl_dealloc_job(job);
1447 1446 }
1448 1447
1449 1448 return (DDI_SUCCESS);
1450 1449 }
1451 1450
1452 1451
1453 1452 /*
1454 1453 * At this time, there shouldn't be any I/O requests on this port.
1455 1454 * But the unsolicited callbacks from the underlying FCA port need
1456 1455 * to be handled very carefully. The steps followed to handle the
1457 1456 * DDI_DETACH are:
1458 1457 * + Grab the port driver mutex, check if the unsolicited
1459 1458 * callback is currently under processing. If true, fail
1460 1459 * the DDI_DETACH request by printing a message; If false
1461 1460 * mark the DDI_DETACH as under progress, so that any
1462 1461 * further unsolicited callbacks get bounced.
1463 1462 * + Perform PRLO/LOGO if necessary, cleanup all the data
1464 1463 * structures.
1465 1464 * + Get the job_handler thread to gracefully exit.
1466 1465 * + Unregister callbacks with the FCA port.
1467 1466 * + Now that some peace is found, notify all the ULPs of
1468 1467 * DDI_DETACH request (using ulp_port_detach entry point)
1469 1468 * + Free all mutexes, semaphores, conditional variables.
1470 1469 * + Free the soft state, return success.
1471 1470 *
1472 1471 * Important considerations:
1473 1472 * Port driver de-registers state change and unsolicited
1474 1473 * callbacks before taking up the task of notifying ULPs
1475 1474 * and performing PRLO and LOGOs.
1476 1475 *
1477 1476 * A port may go offline at the time PRLO/LOGO is being
1478 1477 * requested. It is expected of all FCA drivers to fail
1479 1478 * such requests either immediately with a FC_OFFLINE
1480 1479 * return code to fc_fca_transport() or return the packet
1481 1480 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1482 1481 */
1483 1482 static int
1484 1483 fp_detach_handler(fc_local_port_t *port)
1485 1484 {
1486 1485 job_request_t *job;
1487 1486 uint32_t delay_count;
1488 1487 fc_orphan_t *orp, *tmporp;
1489 1488
1490 1489 /*
1491 1490 * In a Fabric topology with many host ports connected to
1492 1491 * a switch, another detaching instance of fp might have
1493 1492 * triggered a LOGO (which is an unsolicited request to
1494 1493 * this instance). So in order to be able to successfully
1495 1494 * detach by taking care of such cases a delay of about
1496 1495 * 30 seconds is introduced.
1497 1496 */
1498 1497 delay_count = 0;
1499 1498 mutex_enter(&port->fp_mutex);
1500 1499 if (port->fp_out_fpcmds != 0) {
1501 1500 /*
1502 1501 * At this time we can only check fp internal commands, because
1503 1502 * sd/ssd/scsi_vhci should have finsihed all their commands,
1504 1503 * fcp/fcip/fcsm should have finished all their commands.
1505 1504 *
1506 1505 * It seems that all fp internal commands are asynchronous now.
1507 1506 */
1508 1507 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1509 1508 mutex_exit(&port->fp_mutex);
1510 1509
1511 1510 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
1512 1511 " Failing detach", port->fp_instance, port->fp_out_fpcmds);
1513 1512 return (DDI_FAILURE);
1514 1513 }
1515 1514
1516 1515 while ((port->fp_soft_state &
1517 1516 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1518 1517 (delay_count < 30)) {
1519 1518 mutex_exit(&port->fp_mutex);
1520 1519 delay_count++;
1521 1520 delay(drv_usectohz(1000000));
1522 1521 mutex_enter(&port->fp_mutex);
1523 1522 }
1524 1523
1525 1524 if (port->fp_soft_state &
1526 1525 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1527 1526 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1528 1527 mutex_exit(&port->fp_mutex);
1529 1528
1530 1529 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1531 1530 " Failing detach", port->fp_instance);
1532 1531 return (DDI_FAILURE);
1533 1532 }
1534 1533
1535 1534 port->fp_soft_state |= FP_SOFT_IN_DETACH;
1536 1535 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1537 1536 mutex_exit(&port->fp_mutex);
1538 1537
1539 1538 /*
1540 1539 * If we're powered down, we need to raise power prior to submitting
1541 1540 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never
1542 1541 * process the shutdown job.
1543 1542 */
1544 1543 if (fctl_busy_port(port) != 0) {
1545 1544 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1546 1545 port->fp_instance);
1547 1546 mutex_enter(&port->fp_mutex);
1548 1547 port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1549 1548 mutex_exit(&port->fp_mutex);
1550 1549 return (DDI_FAILURE);
1551 1550 }
1552 1551
1553 1552 /*
1554 1553 * This will deallocate data structs and cause the "job" thread
1555 1554 * to exit, in preparation for DDI_DETACH on the instance.
1556 1555 * This can sleep for an arbitrary duration, since it waits for
1557 1556 * commands over the wire, timeout(9F) callbacks, etc.
1558 1557 *
1559 1558 * CAUTION: There is still a race here, where the "job" thread
1560 1559 * can still be executing code even tho the fctl_jobwait() call
1561 1560 * below has returned to us. In theory the fp driver could even be
1562 1561 * modunloaded even tho the job thread isn't done executing.
1563 1562 * without creating the race condition.
1564 1563 */
1565 1564 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1566 1565 (opaque_t)port, KM_SLEEP);
1567 1566 fctl_enque_job(port, job);
1568 1567 fctl_jobwait(job);
1569 1568 fctl_dealloc_job(job);
1570 1569
1571 1570
1572 1571 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1573 1572 FP_PM_PORT_DOWN);
1574 1573
1575 1574 if (port->fp_taskq) {
1576 1575 taskq_destroy(port->fp_taskq);
1577 1576 }
1578 1577
1579 1578 ddi_prop_remove_all(port->fp_port_dip);
1580 1579
1581 1580 ddi_remove_minor_node(port->fp_port_dip, NULL);
1582 1581
1583 1582 fctl_remove_port(port);
1584 1583
1585 1584 fp_free_pkt(port->fp_els_resp_pkt);
1586 1585
1587 1586 if (port->fp_ub_tokens) {
1588 1587 if (fc_ulp_ubfree(port, port->fp_ub_count,
1589 1588 port->fp_ub_tokens) != FC_SUCCESS) {
1590 1589 cmn_err(CE_WARN, "fp(%d): couldn't free "
1591 1590 " unsolicited buffers", port->fp_instance);
1592 1591 }
1593 1592 kmem_free(port->fp_ub_tokens,
1594 1593 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1595 1594 port->fp_ub_tokens = NULL;
1596 1595 }
1597 1596
1598 1597 if (port->fp_pkt_cache != NULL) {
1599 1598 kmem_cache_destroy(port->fp_pkt_cache);
1600 1599 }
1601 1600
1602 1601 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1603 1602
1604 1603 mutex_enter(&port->fp_mutex);
1605 1604 if (port->fp_did_table) {
1606 1605 kmem_free(port->fp_did_table, did_table_size *
1607 1606 sizeof (struct d_id_hash));
1608 1607 }
1609 1608
1610 1609 if (port->fp_pwwn_table) {
1611 1610 kmem_free(port->fp_pwwn_table, pwwn_table_size *
1612 1611 sizeof (struct pwwn_hash));
1613 1612 }
1614 1613 orp = port->fp_orphan_list;
1615 1614 while (orp) {
1616 1615 tmporp = orp;
1617 1616 orp = orp->orp_next;
1618 1617 kmem_free(tmporp, sizeof (*orp));
1619 1618 }
1620 1619
1621 1620 mutex_exit(&port->fp_mutex);
1622 1621
1623 1622 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1624 1623
1625 1624 mutex_destroy(&port->fp_mutex);
1626 1625 cv_destroy(&port->fp_attach_cv);
1627 1626 cv_destroy(&port->fp_cv);
1628 1627 ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1629 1628
1630 1629 return (DDI_SUCCESS);
1631 1630 }
1632 1631
1633 1632
1634 1633 /*
1635 1634 * Steps to perform DDI_SUSPEND operation on a FC port
1636 1635 *
1637 1636 * - If already suspended return DDI_FAILURE
1638 1637 * - If already power-suspended return DDI_SUCCESS
1639 1638 * - If an unsolicited callback or state change handling is in
1640 1639 * in progress, throw a warning message, return DDI_FAILURE
1641 1640 * - Cancel timeouts
1642 1641 * - SUSPEND the job_handler thread (means do nothing as it is
1643 1642 * taken care of by the CPR frame work)
1644 1643 */
1645 1644 static int
1646 1645 fp_suspend_handler(fc_local_port_t *port)
1647 1646 {
1648 1647 uint32_t delay_count;
1649 1648
1650 1649 mutex_enter(&port->fp_mutex);
1651 1650
1652 1651 /*
1653 1652 * The following should never happen, but
1654 1653 * let the driver be more defensive here
1655 1654 */
1656 1655 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1657 1656 mutex_exit(&port->fp_mutex);
1658 1657 return (DDI_FAILURE);
1659 1658 }
1660 1659
1661 1660 /*
1662 1661 * If the port is already power suspended, there
1663 1662 * is nothing else to do, So return DDI_SUCCESS,
1664 1663 * but mark the SUSPEND bit in the soft state
1665 1664 * before leaving.
1666 1665 */
1667 1666 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1668 1667 port->fp_soft_state |= FP_SOFT_SUSPEND;
1669 1668 mutex_exit(&port->fp_mutex);
1670 1669 return (DDI_SUCCESS);
1671 1670 }
1672 1671
1673 1672 /*
1674 1673 * Check if an unsolicited callback or state change handling is
1675 1674 * in progress. If true, fail the suspend operation; also throw
1676 1675 * a warning message notifying the failure. Note that Sun PCI
1677 1676 * hotplug spec recommends messages in cases of failure (but
1678 1677 * not flooding the console)
1679 1678 *
1680 1679 * Busy waiting for a short interval (500 millisecond ?) to see
1681 1680 * if the callback processing completes may be another idea. Since
1682 1681 * most of the callback processing involves a lot of work, it
1683 1682 * is safe to just fail the SUSPEND operation. It is definitely
1684 1683 * not bad to fail the SUSPEND operation if the driver is busy.
1685 1684 */
1686 1685 delay_count = 0;
1687 1686 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1688 1687 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1689 1688 mutex_exit(&port->fp_mutex);
1690 1689 delay_count++;
1691 1690 delay(drv_usectohz(1000000));
1692 1691 mutex_enter(&port->fp_mutex);
1693 1692 }
1694 1693
1695 1694 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1696 1695 FP_SOFT_IN_UNSOL_CB)) {
1697 1696 mutex_exit(&port->fp_mutex);
1698 1697 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1699 1698 " Failing suspend", port->fp_instance);
1700 1699 return (DDI_FAILURE);
1701 1700 }
1702 1701
1703 1702 /*
1704 1703 * Check of FC port thread is busy
1705 1704 */
1706 1705 if (port->fp_job_head) {
1707 1706 mutex_exit(&port->fp_mutex);
1708 1707 FP_TRACE(FP_NHEAD2(9, 0),
1709 1708 "FC port thread is busy: Failing suspend");
1710 1709 return (DDI_FAILURE);
1711 1710 }
1712 1711 port->fp_soft_state |= FP_SOFT_SUSPEND;
1713 1712
1714 1713 fp_suspend_all(port);
1715 1714 mutex_exit(&port->fp_mutex);
1716 1715
1717 1716 return (DDI_SUCCESS);
1718 1717 }
1719 1718
1720 1719
1721 1720 /*
1722 1721 * Prepare for graceful power down of a FC port
1723 1722 */
1724 1723 static int
1725 1724 fp_power_down(fc_local_port_t *port)
1726 1725 {
1727 1726 ASSERT(MUTEX_HELD(&port->fp_mutex));
1728 1727
1729 1728 /*
1730 1729 * Power down request followed by a DDI_SUSPEND should
1731 1730 * never happen; If it does return DDI_SUCCESS
1732 1731 */
1733 1732 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1734 1733 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1735 1734 return (DDI_SUCCESS);
1736 1735 }
1737 1736
1738 1737 /*
1739 1738 * If the port is already power suspended, there
1740 1739 * is nothing else to do, So return DDI_SUCCESS,
1741 1740 */
1742 1741 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1743 1742 return (DDI_SUCCESS);
1744 1743 }
1745 1744
1746 1745 /*
1747 1746 * Check if an unsolicited callback or state change handling
1748 1747 * is in progress. If true, fail the PM suspend operation.
1749 1748 * But don't print a message unless the verbosity of the
1750 1749 * driver desires otherwise.
1751 1750 */
1752 1751 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1753 1752 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1754 1753 FP_TRACE(FP_NHEAD2(9, 0),
1755 1754 "Unsolicited callback in progress: Failing power down");
1756 1755 return (DDI_FAILURE);
1757 1756 }
1758 1757
1759 1758 /*
1760 1759 * Check of FC port thread is busy
1761 1760 */
1762 1761 if (port->fp_job_head) {
1763 1762 FP_TRACE(FP_NHEAD2(9, 0),
1764 1763 "FC port thread is busy: Failing power down");
1765 1764 return (DDI_FAILURE);
1766 1765 }
1767 1766 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1768 1767
1769 1768 /*
1770 1769 * check if the ULPs are ready for power down
1771 1770 */
1772 1771 mutex_exit(&port->fp_mutex);
1773 1772 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1774 1773 &modlinkage) != FC_SUCCESS) {
1775 1774 mutex_enter(&port->fp_mutex);
1776 1775 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1777 1776 mutex_exit(&port->fp_mutex);
1778 1777
1779 1778 /*
1780 1779 * Power back up the obedient ULPs that went down
1781 1780 */
1782 1781 fp_attach_ulps(port, FC_CMD_POWER_UP);
1783 1782
1784 1783 FP_TRACE(FP_NHEAD2(9, 0),
1785 1784 "ULP(s) busy, detach_ulps failed. Failing power down");
1786 1785 mutex_enter(&port->fp_mutex);
1787 1786 return (DDI_FAILURE);
1788 1787 }
1789 1788 mutex_enter(&port->fp_mutex);
1790 1789
1791 1790 fp_suspend_all(port);
1792 1791
1793 1792 return (DDI_SUCCESS);
1794 1793 }
1795 1794
1796 1795
1797 1796 /*
1798 1797 * Suspend the entire FC port
1799 1798 */
1800 1799 static void
1801 1800 fp_suspend_all(fc_local_port_t *port)
1802 1801 {
1803 1802 int index;
1804 1803 struct pwwn_hash *head;
1805 1804 fc_remote_port_t *pd;
1806 1805
1807 1806 ASSERT(MUTEX_HELD(&port->fp_mutex));
1808 1807
1809 1808 if (port->fp_wait_tid != 0) {
1810 1809 timeout_id_t tid;
1811 1810
1812 1811 tid = port->fp_wait_tid;
1813 1812 port->fp_wait_tid = (timeout_id_t)NULL;
1814 1813 mutex_exit(&port->fp_mutex);
1815 1814 (void) untimeout(tid);
1816 1815 mutex_enter(&port->fp_mutex);
1817 1816 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1818 1817 }
1819 1818
1820 1819 if (port->fp_offline_tid) {
1821 1820 timeout_id_t tid;
1822 1821
1823 1822 tid = port->fp_offline_tid;
1824 1823 port->fp_offline_tid = (timeout_id_t)NULL;
1825 1824 mutex_exit(&port->fp_mutex);
1826 1825 (void) untimeout(tid);
1827 1826 mutex_enter(&port->fp_mutex);
1828 1827 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1829 1828 }
1830 1829 mutex_exit(&port->fp_mutex);
1831 1830 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1832 1831 mutex_enter(&port->fp_mutex);
1833 1832
1834 1833 /*
1835 1834 * Mark all devices as OLD, and reset the LOGIN state as well
1836 1835 * (this will force the ULPs to perform a LOGIN after calling
1837 1836 * fc_portgetmap() during RESUME/PM_RESUME)
1838 1837 */
1839 1838 for (index = 0; index < pwwn_table_size; index++) {
1840 1839 head = &port->fp_pwwn_table[index];
1841 1840 pd = head->pwwn_head;
1842 1841 while (pd != NULL) {
1843 1842 mutex_enter(&pd->pd_mutex);
1844 1843 fp_remote_port_offline(pd);
1845 1844 fctl_delist_did_table(port, pd);
1846 1845 pd->pd_state = PORT_DEVICE_VALID;
1847 1846 pd->pd_login_count = 0;
1848 1847 mutex_exit(&pd->pd_mutex);
1849 1848 pd = pd->pd_wwn_hnext;
1850 1849 }
1851 1850 }
1852 1851 }
1853 1852
1854 1853
1855 1854 /*
1856 1855 * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1857 1856 * Performs intializations for fc_packet_t structs.
1858 1857 * Returns 0 for success or -1 for failure.
1859 1858 *
1860 1859 * This function allocates DMA handles for both command and responses.
1861 1860 * Most of the ELSs used have both command and responses so it is strongly
1862 1861 * desired to move them to cache constructor routine.
1863 1862 *
1864 1863 * Context: Can sleep iff called with KM_SLEEP flag.
1865 1864 */
1866 1865 static int
1867 1866 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1868 1867 {
1869 1868 int (*cb) (caddr_t);
1870 1869 fc_packet_t *pkt;
1871 1870 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1872 1871 fc_local_port_t *port = (fc_local_port_t *)cdarg;
1873 1872
1874 1873 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1875 1874
1876 1875 cmd->cmd_next = NULL;
1877 1876 cmd->cmd_flags = 0;
1878 1877 cmd->cmd_dflags = 0;
1879 1878 cmd->cmd_job = NULL;
1880 1879 cmd->cmd_port = port;
1881 1880 pkt = &cmd->cmd_pkt;
1882 1881
1883 1882 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
1884 1883 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1885 1884 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1886 1885 &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1887 1886 return (-1);
1888 1887 }
1889 1888
1890 1889 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1891 1890 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1892 1891 &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1893 1892 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1894 1893 return (-1);
1895 1894 }
1896 1895 } else {
1897 1896 pkt->pkt_cmd_dma = 0;
1898 1897 pkt->pkt_resp_dma = 0;
1899 1898 }
1900 1899
1901 1900 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1902 1901 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1903 1902 pkt->pkt_data_cookie_cnt = 0;
1904 1903 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1905 1904 pkt->pkt_data_cookie = NULL;
1906 1905 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1907 1906
1908 1907 return (0);
1909 1908 }
1910 1909
1911 1910
1912 1911 /*
1913 1912 * fp_cache_destructor: Destructor function for kmem_cache_create().
1914 1913 * Performs un-intializations for fc_packet_t structs.
1915 1914 */
1916 1915 /* ARGSUSED */
1917 1916 static void
1918 1917 fp_cache_destructor(void *buf, void *cdarg)
1919 1918 {
1920 1919 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1921 1920 fc_packet_t *pkt;
1922 1921
1923 1922 pkt = &cmd->cmd_pkt;
1924 1923 if (pkt->pkt_cmd_dma) {
1925 1924 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1926 1925 }
1927 1926
1928 1927 if (pkt->pkt_resp_dma) {
1929 1928 ddi_dma_free_handle(&pkt->pkt_resp_dma);
1930 1929 }
1931 1930 }
1932 1931
1933 1932
1934 1933 /*
1935 1934 * Packet allocation for ELS and any other port driver commands
1936 1935 *
1937 1936 * Some ELSs like FLOGI and PLOGI are critical for topology and
1938 1937 * device discovery and a system's inability to allocate memory
1939 1938 * or DVMA resources while performing some of these critical ELSs
1940 1939 * cause a lot of problem. While memory allocation failures are
1941 1940 * rare, DVMA resource failures are common as the applications
1942 1941 * are becoming more and more powerful on huge servers. So it
1943 1942 * is desirable to have a framework support to reserve a fragment
1944 1943 * of DVMA. So until this is fixed the correct way, the suffering
1945 1944 * is huge whenever a LIP happens at a time DVMA resources are
1946 1945 * drained out completely - So an attempt needs to be made to
1947 1946 * KM_SLEEP while requesting for these resources, hoping that
1948 1947 * the requests won't hang forever.
1949 1948 *
1950 1949 * The fc_remote_port_t argument is stored into the pkt_pd field in the
1951 1950 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This
1952 1951 * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1953 1952 * If there is no fc_remote_port_t associated with the fc_packet_t, then
1954 1953 * fp_alloc_pkt() must be called with pd set to NULL.
1955 1954 *
1956 1955 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
1957 1956 * actually, it's a design fault. But there's no problem for physical
1958 1957 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
1959 1958 *
1960 1959 * For FCAs that don't support DMA, such as fcoei, we will use
1961 1960 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
1962 1961 */
1963 1962
1964 1963 static fp_cmd_t *
1965 1964 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1966 1965 fc_remote_port_t *pd)
1967 1966 {
1968 1967 int rval;
1969 1968 ulong_t real_len;
1970 1969 fp_cmd_t *cmd;
1971 1970 fc_packet_t *pkt;
1972 1971 int (*cb) (caddr_t);
1973 1972 ddi_dma_cookie_t pkt_cookie;
1974 1973 ddi_dma_cookie_t *cp;
1975 1974 uint32_t cnt;
1976 1975
1977 1976 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1978 1977
1979 1978 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1980 1979
1981 1980 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1982 1981 if (cmd == NULL) {
1983 1982 return (cmd);
1984 1983 }
1985 1984
1986 1985 cmd->cmd_ulp_pkt = NULL;
1987 1986 cmd->cmd_flags = 0;
1988 1987 pkt = &cmd->cmd_pkt;
1989 1988 ASSERT(cmd->cmd_dflags == 0);
1990 1989
1991 1990 pkt->pkt_datalen = 0;
1992 1991 pkt->pkt_data = NULL;
1993 1992 pkt->pkt_state = 0;
1994 1993 pkt->pkt_action = 0;
1995 1994 pkt->pkt_reason = 0;
1996 1995 pkt->pkt_expln = 0;
1997 1996 pkt->pkt_cmd = NULL;
1998 1997 pkt->pkt_resp = NULL;
1999 1998 pkt->pkt_fctl_rsvd1 = NULL;
2000 1999 pkt->pkt_fctl_rsvd2 = NULL;
2001 2000
2002 2001 /*
2003 2002 * Init pkt_pd with the given pointer; this must be done _before_
2004 2003 * the call to fc_ulp_init_packet().
2005 2004 */
2006 2005 pkt->pkt_pd = pd;
2007 2006
2008 2007 /* Now call the FCA driver to init its private, per-packet fields */
2009 2008 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
2010 2009 goto alloc_pkt_failed;
2011 2010 }
2012 2011
2013 2012 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2014 2013 ASSERT(pkt->pkt_cmd_dma != NULL);
2015 2014
2016 2015 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2017 2016 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
2018 2017 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2019 2018 &pkt->pkt_cmd_acc);
2020 2019
2021 2020 if (rval != DDI_SUCCESS) {
2022 2021 goto alloc_pkt_failed;
2023 2022 }
2024 2023 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
2025 2024
2026 2025 if (real_len < cmd_len) {
2027 2026 goto alloc_pkt_failed;
2028 2027 }
2029 2028
2030 2029 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2031 2030 pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2032 2031 DDI_DMA_CONSISTENT, cb, NULL,
2033 2032 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2034 2033
2035 2034 if (rval != DDI_DMA_MAPPED) {
2036 2035 goto alloc_pkt_failed;
2037 2036 }
2038 2037
2039 2038 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2040 2039
2041 2040 if (pkt->pkt_cmd_cookie_cnt >
2042 2041 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2043 2042 goto alloc_pkt_failed;
2044 2043 }
2045 2044
2046 2045 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2047 2046
2048 2047 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2049 2048 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2050 2049 KM_NOSLEEP);
2051 2050
2052 2051 if (cp == NULL) {
2053 2052 goto alloc_pkt_failed;
2054 2053 }
2055 2054
2056 2055 *cp = pkt_cookie;
2057 2056 cp++;
2058 2057 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2059 2058 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2060 2059 *cp = pkt_cookie;
2061 2060 }
2062 2061 } else if (cmd_len != 0) {
2063 2062 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
2064 2063 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
2065 2064 }
2066 2065
2067 2066 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2068 2067 ASSERT(pkt->pkt_resp_dma != NULL);
2069 2068
2070 2069 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2071 2070 port->fp_fca_tran->fca_acc_attr,
2072 2071 DDI_DMA_CONSISTENT, cb, NULL,
2073 2072 (caddr_t *)&pkt->pkt_resp, &real_len,
2074 2073 &pkt->pkt_resp_acc);
2075 2074
2076 2075 if (rval != DDI_SUCCESS) {
2077 2076 goto alloc_pkt_failed;
2078 2077 }
2079 2078 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2080 2079
2081 2080 if (real_len < resp_len) {
2082 2081 goto alloc_pkt_failed;
2083 2082 }
2084 2083
2085 2084 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2086 2085 pkt->pkt_resp, real_len, DDI_DMA_READ |
2087 2086 DDI_DMA_CONSISTENT, cb, NULL,
2088 2087 &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2089 2088
2090 2089 if (rval != DDI_DMA_MAPPED) {
2091 2090 goto alloc_pkt_failed;
2092 2091 }
2093 2092
2094 2093 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2095 2094
2096 2095 if (pkt->pkt_resp_cookie_cnt >
2097 2096 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2098 2097 goto alloc_pkt_failed;
2099 2098 }
2100 2099
2101 2100 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2102 2101
2103 2102 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2104 2103 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2105 2104 KM_NOSLEEP);
2106 2105
2107 2106 if (cp == NULL) {
2108 2107 goto alloc_pkt_failed;
2109 2108 }
2110 2109
2111 2110 *cp = pkt_cookie;
2112 2111 cp++;
2113 2112 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2114 2113 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2115 2114 *cp = pkt_cookie;
2116 2115 }
2117 2116 } else if (resp_len != 0) {
2118 2117 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
2119 2118 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
2120 2119 }
2121 2120
2122 2121 pkt->pkt_cmdlen = cmd_len;
2123 2122 pkt->pkt_rsplen = resp_len;
2124 2123 pkt->pkt_ulp_private = cmd;
2125 2124
2126 2125 return (cmd);
2127 2126
2128 2127 alloc_pkt_failed:
2129 2128
2130 2129 fp_free_dma(cmd);
2131 2130
2132 2131 if (pkt->pkt_cmd_cookie != NULL) {
2133 2132 kmem_free(pkt->pkt_cmd_cookie,
2134 2133 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2135 2134 pkt->pkt_cmd_cookie = NULL;
2136 2135 }
2137 2136
2138 2137 if (pkt->pkt_resp_cookie != NULL) {
2139 2138 kmem_free(pkt->pkt_resp_cookie,
2140 2139 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2141 2140 pkt->pkt_resp_cookie = NULL;
2142 2141 }
2143 2142
2144 2143 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2145 2144 if (pkt->pkt_cmd) {
2146 2145 kmem_free(pkt->pkt_cmd, cmd_len);
2147 2146 }
2148 2147
2149 2148 if (pkt->pkt_resp) {
2150 2149 kmem_free(pkt->pkt_resp, resp_len);
2151 2150 }
2152 2151 }
2153 2152
2154 2153 kmem_cache_free(port->fp_pkt_cache, cmd);
2155 2154
2156 2155 return (NULL);
2157 2156 }
2158 2157
2159 2158
2160 2159 /*
2161 2160 * Free FC packet
2162 2161 */
2163 2162 static void
2164 2163 fp_free_pkt(fp_cmd_t *cmd)
2165 2164 {
2166 2165 fc_local_port_t *port;
2167 2166 fc_packet_t *pkt;
2168 2167
2169 2168 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2170 2169
2171 2170 cmd->cmd_next = NULL;
2172 2171 cmd->cmd_job = NULL;
2173 2172 pkt = &cmd->cmd_pkt;
2174 2173 pkt->pkt_ulp_private = 0;
2175 2174 pkt->pkt_tran_flags = 0;
2176 2175 pkt->pkt_tran_type = 0;
2177 2176 port = cmd->cmd_port;
2178 2177
2179 2178 if (pkt->pkt_cmd_cookie != NULL) {
2180 2179 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2181 2180 sizeof (ddi_dma_cookie_t));
2182 2181 pkt->pkt_cmd_cookie = NULL;
2183 2182 }
2184 2183
2185 2184 if (pkt->pkt_resp_cookie != NULL) {
2186 2185 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2187 2186 sizeof (ddi_dma_cookie_t));
2188 2187 pkt->pkt_resp_cookie = NULL;
2189 2188 }
2190 2189
2191 2190 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2192 2191 if (pkt->pkt_cmd) {
2193 2192 kmem_free(pkt->pkt_cmd,
2194 2193 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
2195 2194 }
2196 2195
2197 2196 if (pkt->pkt_resp) {
2198 2197 kmem_free(pkt->pkt_resp,
2199 2198 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
2200 2199 }
2201 2200 }
2202 2201
2203 2202 fp_free_dma(cmd);
2204 2203 (void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2205 2204 kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2206 2205 }
2207 2206
2208 2207
2209 2208 /*
2210 2209 * Release DVMA resources
2211 2210 */
2212 2211 static void
2213 2212 fp_free_dma(fp_cmd_t *cmd)
2214 2213 {
2215 2214 fc_packet_t *pkt = &cmd->cmd_pkt;
2216 2215
2217 2216 pkt->pkt_cmdlen = 0;
2218 2217 pkt->pkt_rsplen = 0;
2219 2218 pkt->pkt_tran_type = 0;
2220 2219 pkt->pkt_tran_flags = 0;
2221 2220
2222 2221 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2223 2222 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2224 2223 }
2225 2224
2226 2225 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2227 2226 if (pkt->pkt_cmd_acc) {
2228 2227 ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2229 2228 }
2230 2229 }
2231 2230
2232 2231 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2233 2232 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2234 2233 }
2235 2234
2236 2235 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2237 2236 if (pkt->pkt_resp_acc) {
2238 2237 ddi_dma_mem_free(&pkt->pkt_resp_acc);
2239 2238 }
2240 2239 }
2241 2240 cmd->cmd_dflags = 0;
2242 2241 }
2243 2242
2244 2243
2245 2244 /*
2246 2245 * Dedicated thread to perform various activities. One thread for
2247 2246 * each fc_local_port_t (driver soft state) instance.
2248 2247 * Note, this effectively works out to one thread for each local
2249 2248 * port, but there are also some Solaris taskq threads in use on a per-local
2250 2249 * port basis; these also need to be taken into consideration.
2251 2250 */
2252 2251 static void
2253 2252 fp_job_handler(fc_local_port_t *port)
2254 2253 {
2255 2254 int rval;
2256 2255 uint32_t *d_id;
2257 2256 fc_remote_port_t *pd;
2258 2257 job_request_t *job;
2259 2258
2260 2259 #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 2266 #endif
2268 2267
2269 2268
2270 2269 /* Loop forever waiting for work to do */
2271 2270 for (;;) {
2272 2271
2273 2272 mutex_enter(&port->fp_mutex);
2274 2273
2275 2274 /*
2276 2275 * Sleep if no work to do right now, or if we want
2277 2276 * to suspend or power-down.
2278 2277 */
2279 2278 while (port->fp_job_head == NULL ||
2280 2279 (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2281 2280 FP_SOFT_SUSPEND))) {
2282 2281 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2283 2282 cv_wait(&port->fp_cv, &port->fp_mutex);
2284 2283 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2285 2284 }
2286 2285
2287 2286 /*
2288 2287 * OK, we've just been woken up, so retrieve the next entry
2289 2288 * from the head of the job queue for this local port.
2290 2289 */
2291 2290 job = fctl_deque_job(port);
2292 2291
2293 2292 /*
2294 2293 * Handle all the fp driver's supported job codes here
2295 2294 * in this big honkin' switch.
2296 2295 */
2297 2296 switch (job->job_code) {
2298 2297 case JOB_PORT_SHUTDOWN:
2299 2298 /*
2300 2299 * fp_port_shutdown() is only called from here. This
2301 2300 * will prepare the local port instance (softstate)
2302 2301 * for detaching. This cancels timeout callbacks,
2303 2302 * executes LOGOs with remote ports, cleans up tables,
2304 2303 * and deallocates data structs.
2305 2304 */
2306 2305 fp_port_shutdown(port, job);
2307 2306
2308 2307 /*
2309 2308 * This will exit the job thread.
2310 2309 */
2311 2310 #ifndef __lock_lint
2312 2311 CALLB_CPR_EXIT(&(port->fp_cpr_info));
2313 2312 #else
2314 2313 mutex_exit(&port->fp_mutex);
2315 2314 #endif
2316 2315 fctl_jobdone(job);
2317 2316 thread_exit();
2318 2317
2319 2318 /* NOTREACHED */
2320 2319
2321 2320 case JOB_ATTACH_ULP: {
2322 2321 /*
2323 2322 * This job is spawned in response to a ULP calling
2324 2323 * fc_ulp_add().
2325 2324 */
2326 2325
2327 2326 boolean_t do_attach_ulps = B_TRUE;
2328 2327
2329 2328 /*
2330 2329 * If fp is detaching, we don't want to call
2331 2330 * fp_startup_done as this asynchronous
2332 2331 * notification may interfere with the re-attach.
2333 2332 */
2334 2333
2335 2334 if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2336 2335 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2337 2336 do_attach_ulps = B_FALSE;
2338 2337 } else {
2339 2338 /*
2340 2339 * We are going to force the transport
2341 2340 * to attach to the ULPs, so set
2342 2341 * fp_ulp_attach. This will keep any
2343 2342 * potential detach from occurring until
2344 2343 * we are done.
2345 2344 */
2346 2345 port->fp_ulp_attach = 1;
2347 2346 }
2348 2347
2349 2348 mutex_exit(&port->fp_mutex);
2350 2349
2351 2350 /*
2352 2351 * NOTE: Since we just dropped the mutex, there is now
2353 2352 * a race window where the fp_soft_state check above
2354 2353 * could change here. This race is covered because an
2355 2354 * additional check was added in the functions hidden
2356 2355 * under fp_startup_done().
2357 2356 */
2358 2357 if (do_attach_ulps == B_TRUE) {
2359 2358 /*
2360 2359 * This goes thru a bit of a convoluted call
2361 2360 * chain before spawning off a DDI taskq
2362 2361 * request to perform the actual attach
2363 2362 * operations. Blocking can occur at a number
2364 2363 * of points.
2365 2364 */
2366 2365 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2367 2366 }
2368 2367 job->job_result = FC_SUCCESS;
2369 2368 fctl_jobdone(job);
2370 2369 break;
2371 2370 }
2372 2371
2373 2372 case JOB_ULP_NOTIFY: {
2374 2373 /*
2375 2374 * Pass state change notifications up to any/all
2376 2375 * registered ULPs.
2377 2376 */
2378 2377 uint32_t statec;
2379 2378
2380 2379 statec = job->job_ulp_listlen;
2381 2380 if (statec == FC_STATE_RESET_REQUESTED) {
2382 2381 port->fp_last_task = port->fp_task;
2383 2382 port->fp_task = FP_TASK_OFFLINE;
2384 2383 fp_port_offline(port, 0);
2385 2384 port->fp_task = port->fp_last_task;
2386 2385 port->fp_last_task = FP_TASK_IDLE;
2387 2386 }
2388 2387
2389 2388 if (--port->fp_statec_busy == 0) {
2390 2389 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2391 2390 }
2392 2391
2393 2392 mutex_exit(&port->fp_mutex);
2394 2393
2395 2394 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2396 2395 fctl_jobdone(job);
2397 2396 break;
2398 2397 }
2399 2398
2400 2399 case JOB_PLOGI_ONE:
2401 2400 /*
2402 2401 * Issue a PLOGI to a single remote port. Multiple
2403 2402 * PLOGIs to different remote ports may occur in
2404 2403 * parallel.
2405 2404 * This can create the fc_remote_port_t if it does not
2406 2405 * already exist.
2407 2406 */
2408 2407
2409 2408 mutex_exit(&port->fp_mutex);
2410 2409 d_id = (uint32_t *)job->job_private;
2411 2410 pd = fctl_get_remote_port_by_did(port, *d_id);
2412 2411
2413 2412 if (pd) {
2414 2413 mutex_enter(&pd->pd_mutex);
2415 2414 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2416 2415 pd->pd_login_count++;
2417 2416 mutex_exit(&pd->pd_mutex);
2418 2417 job->job_result = FC_SUCCESS;
2419 2418 fctl_jobdone(job);
2420 2419 break;
2421 2420 }
2422 2421 mutex_exit(&pd->pd_mutex);
2423 2422 } else {
2424 2423 mutex_enter(&port->fp_mutex);
2425 2424 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2426 2425 mutex_exit(&port->fp_mutex);
2427 2426 pd = fp_create_remote_port_by_ns(port,
2428 2427 *d_id, KM_SLEEP);
2429 2428 if (pd == NULL) {
2430 2429 job->job_result = FC_FAILURE;
2431 2430 fctl_jobdone(job);
2432 2431 break;
2433 2432 }
2434 2433 } else {
2435 2434 mutex_exit(&port->fp_mutex);
2436 2435 }
2437 2436 }
2438 2437
2439 2438 job->job_flags |= JOB_TYPE_FP_ASYNC;
2440 2439 job->job_counter = 1;
2441 2440
2442 2441 rval = fp_port_login(port, *d_id, job,
2443 2442 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2444 2443
2445 2444 if (rval != FC_SUCCESS) {
2446 2445 job->job_result = rval;
2447 2446 fctl_jobdone(job);
2448 2447 }
2449 2448 break;
2450 2449
2451 2450 case JOB_LOGO_ONE: {
2452 2451 /*
2453 2452 * Issue a PLOGO to a single remote port. Multiple
2454 2453 * PLOGOs to different remote ports may occur in
2455 2454 * parallel.
2456 2455 */
2457 2456 fc_remote_port_t *pd;
2458 2457
2459 2458 #ifndef __lock_lint
2460 2459 ASSERT(job->job_counter > 0);
2461 2460 #endif
2462 2461
2463 2462 pd = (fc_remote_port_t *)job->job_ulp_pkts;
2464 2463
2465 2464 mutex_enter(&pd->pd_mutex);
2466 2465 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2467 2466 mutex_exit(&pd->pd_mutex);
2468 2467 job->job_result = FC_LOGINREQ;
2469 2468 mutex_exit(&port->fp_mutex);
2470 2469 fctl_jobdone(job);
2471 2470 break;
2472 2471 }
2473 2472 if (pd->pd_login_count > 1) {
2474 2473 pd->pd_login_count--;
2475 2474 mutex_exit(&pd->pd_mutex);
2476 2475 job->job_result = FC_SUCCESS;
2477 2476 mutex_exit(&port->fp_mutex);
2478 2477 fctl_jobdone(job);
2479 2478 break;
2480 2479 }
2481 2480 mutex_exit(&pd->pd_mutex);
2482 2481 mutex_exit(&port->fp_mutex);
2483 2482 job->job_flags |= JOB_TYPE_FP_ASYNC;
2484 2483 (void) fp_logout(port, pd, job);
2485 2484 break;
2486 2485 }
2487 2486
2488 2487 case JOB_FCIO_LOGIN:
2489 2488 /*
2490 2489 * PLOGI initiated at ioctl request.
2491 2490 */
2492 2491 mutex_exit(&port->fp_mutex);
2493 2492 job->job_result =
2494 2493 fp_fcio_login(port, job->job_private, job);
2495 2494 fctl_jobdone(job);
2496 2495 break;
2497 2496
2498 2497 case JOB_FCIO_LOGOUT:
2499 2498 /*
2500 2499 * PLOGO initiated at ioctl request.
2501 2500 */
2502 2501 mutex_exit(&port->fp_mutex);
2503 2502 job->job_result =
2504 2503 fp_fcio_logout(port, job->job_private, job);
2505 2504 fctl_jobdone(job);
2506 2505 break;
2507 2506
2508 2507 case JOB_PORT_GETMAP:
2509 2508 case JOB_PORT_GETMAP_PLOGI_ALL: {
2510 2509 port->fp_last_task = port->fp_task;
2511 2510 port->fp_task = FP_TASK_GETMAP;
2512 2511
2513 2512 switch (port->fp_topology) {
2514 2513 case FC_TOP_PRIVATE_LOOP:
2515 2514 job->job_counter = 1;
2516 2515
2517 2516 fp_get_loopmap(port, job);
2518 2517 mutex_exit(&port->fp_mutex);
2519 2518 fp_jobwait(job);
2520 2519 fctl_fillout_map(port,
2521 2520 (fc_portmap_t **)job->job_private,
2522 2521 (uint32_t *)job->job_arg, 1, 0, 0);
2523 2522 fctl_jobdone(job);
2524 2523 mutex_enter(&port->fp_mutex);
2525 2524 break;
2526 2525
2527 2526 case FC_TOP_PUBLIC_LOOP:
2528 2527 case FC_TOP_FABRIC:
2529 2528 mutex_exit(&port->fp_mutex);
2530 2529 job->job_counter = 1;
2531 2530
2532 2531 job->job_result = fp_ns_getmap(port,
2533 2532 job, (fc_portmap_t **)job->job_private,
2534 2533 (uint32_t *)job->job_arg,
2535 2534 FCTL_GAN_START_ID);
2536 2535 fctl_jobdone(job);
2537 2536 mutex_enter(&port->fp_mutex);
2538 2537 break;
2539 2538
2540 2539 case FC_TOP_PT_PT:
2541 2540 mutex_exit(&port->fp_mutex);
2542 2541 fctl_fillout_map(port,
2543 2542 (fc_portmap_t **)job->job_private,
2544 2543 (uint32_t *)job->job_arg, 1, 0, 0);
2545 2544 fctl_jobdone(job);
2546 2545 mutex_enter(&port->fp_mutex);
2547 2546 break;
2548 2547
2549 2548 default:
2550 2549 mutex_exit(&port->fp_mutex);
2551 2550 fctl_jobdone(job);
2552 2551 mutex_enter(&port->fp_mutex);
2553 2552 break;
2554 2553 }
2555 2554 port->fp_task = port->fp_last_task;
2556 2555 port->fp_last_task = FP_TASK_IDLE;
2557 2556 mutex_exit(&port->fp_mutex);
2558 2557 break;
2559 2558 }
2560 2559
2561 2560 case JOB_PORT_OFFLINE: {
2562 2561 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2563 2562
2564 2563 port->fp_last_task = port->fp_task;
2565 2564 port->fp_task = FP_TASK_OFFLINE;
2566 2565
2567 2566 if (port->fp_statec_busy > 2) {
2568 2567 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2569 2568 fp_port_offline(port, 0);
2570 2569 if (--port->fp_statec_busy == 0) {
2571 2570 port->fp_soft_state &=
2572 2571 ~FP_SOFT_IN_STATEC_CB;
2573 2572 }
2574 2573 } else {
2575 2574 fp_port_offline(port, 1);
2576 2575 }
2577 2576
2578 2577 port->fp_task = port->fp_last_task;
2579 2578 port->fp_last_task = FP_TASK_IDLE;
2580 2579
2581 2580 mutex_exit(&port->fp_mutex);
2582 2581
2583 2582 fctl_jobdone(job);
2584 2583 break;
2585 2584 }
2586 2585
2587 2586 case JOB_PORT_STARTUP: {
2588 2587 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2589 2588 if (port->fp_statec_busy > 1) {
2590 2589 mutex_exit(&port->fp_mutex);
2591 2590 break;
2592 2591 }
2593 2592 mutex_exit(&port->fp_mutex);
2594 2593
2595 2594 FP_TRACE(FP_NHEAD2(9, rval),
2596 2595 "Topology discovery failed");
2597 2596 break;
2598 2597 }
2599 2598
2600 2599 /*
2601 2600 * Attempt building device handles in case
2602 2601 * of private Loop.
2603 2602 */
2604 2603 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2605 2604 job->job_counter = 1;
2606 2605
2607 2606 fp_get_loopmap(port, job);
2608 2607 mutex_exit(&port->fp_mutex);
2609 2608 fp_jobwait(job);
2610 2609 mutex_enter(&port->fp_mutex);
2611 2610 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2612 2611 ASSERT(port->fp_total_devices == 0);
2613 2612 port->fp_total_devices =
2614 2613 port->fp_dev_count;
2615 2614 }
2616 2615 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2617 2616 /*
2618 2617 * Hack to avoid state changes going up early
2619 2618 */
2620 2619 port->fp_statec_busy++;
2621 2620 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2622 2621
2623 2622 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2624 2623 fp_fabric_online(port, job);
2625 2624 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2626 2625 }
2627 2626 mutex_exit(&port->fp_mutex);
2628 2627 fctl_jobdone(job);
2629 2628 break;
2630 2629 }
2631 2630
2632 2631 case JOB_PORT_ONLINE: {
2633 2632 char *newtop;
2634 2633 char *oldtop;
2635 2634 uint32_t old_top;
2636 2635
2637 2636 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2638 2637
2639 2638 /*
2640 2639 * Bail out early if there are a lot of
2641 2640 * state changes in the pipeline
2642 2641 */
2643 2642 if (port->fp_statec_busy > 1) {
2644 2643 --port->fp_statec_busy;
2645 2644 mutex_exit(&port->fp_mutex);
2646 2645 fctl_jobdone(job);
2647 2646 break;
2648 2647 }
2649 2648
2650 2649 switch (old_top = port->fp_topology) {
2651 2650 case FC_TOP_PRIVATE_LOOP:
2652 2651 oldtop = "Private Loop";
2653 2652 break;
2654 2653
2655 2654 case FC_TOP_PUBLIC_LOOP:
2656 2655 oldtop = "Public Loop";
2657 2656 break;
2658 2657
2659 2658 case FC_TOP_PT_PT:
2660 2659 oldtop = "Point to Point";
2661 2660 break;
2662 2661
2663 2662 case FC_TOP_FABRIC:
2664 2663 oldtop = "Fabric";
2665 2664 break;
2666 2665
2667 2666 default:
2668 2667 oldtop = NULL;
2669 2668 break;
2670 2669 }
2671 2670
2672 2671 port->fp_last_task = port->fp_task;
2673 2672 port->fp_task = FP_TASK_ONLINE;
2674 2673
2675 2674 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2676 2675
2677 2676 port->fp_task = port->fp_last_task;
2678 2677 port->fp_last_task = FP_TASK_IDLE;
2679 2678
2680 2679 if (port->fp_statec_busy > 1) {
2681 2680 --port->fp_statec_busy;
2682 2681 mutex_exit(&port->fp_mutex);
2683 2682 break;
2684 2683 }
2685 2684
2686 2685 port->fp_state = FC_STATE_OFFLINE;
2687 2686
2688 2687 FP_TRACE(FP_NHEAD2(9, rval),
2689 2688 "Topology discovery failed");
2690 2689
2691 2690 if (--port->fp_statec_busy == 0) {
2692 2691 port->fp_soft_state &=
2693 2692 ~FP_SOFT_IN_STATEC_CB;
2694 2693 }
2695 2694
2696 2695 if (port->fp_offline_tid == NULL) {
2697 2696 port->fp_offline_tid =
2698 2697 timeout(fp_offline_timeout,
2699 2698 (caddr_t)port, fp_offline_ticks);
2700 2699 }
2701 2700
2702 2701 mutex_exit(&port->fp_mutex);
2703 2702 break;
2704 2703 }
2705 2704
2706 2705 switch (port->fp_topology) {
2707 2706 case FC_TOP_PRIVATE_LOOP:
2708 2707 newtop = "Private Loop";
2709 2708 break;
2710 2709
2711 2710 case FC_TOP_PUBLIC_LOOP:
2712 2711 newtop = "Public Loop";
2713 2712 break;
2714 2713
2715 2714 case FC_TOP_PT_PT:
2716 2715 newtop = "Point to Point";
2717 2716 break;
2718 2717
2719 2718 case FC_TOP_FABRIC:
2720 2719 newtop = "Fabric";
2721 2720 break;
2722 2721
2723 2722 default:
2724 2723 newtop = NULL;
2725 2724 break;
2726 2725 }
2727 2726
2728 2727 if (oldtop && newtop && strcmp(oldtop, newtop)) {
2729 2728 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2730 2729 "Change in FC Topology old = %s new = %s",
2731 2730 oldtop, newtop);
2732 2731 }
2733 2732
2734 2733 switch (port->fp_topology) {
2735 2734 case FC_TOP_PRIVATE_LOOP: {
2736 2735 int orphan = (old_top == FC_TOP_FABRIC ||
2737 2736 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2738 2737
2739 2738 mutex_exit(&port->fp_mutex);
2740 2739 fp_loop_online(port, job, orphan);
2741 2740 break;
2742 2741 }
2743 2742
2744 2743 case FC_TOP_PUBLIC_LOOP:
2745 2744 /* FALLTHROUGH */
2746 2745 case FC_TOP_FABRIC:
2747 2746 fp_fabric_online(port, job);
2748 2747 mutex_exit(&port->fp_mutex);
2749 2748 break;
2750 2749
2751 2750 case FC_TOP_PT_PT:
2752 2751 fp_p2p_online(port, job);
2753 2752 mutex_exit(&port->fp_mutex);
2754 2753 break;
2755 2754
2756 2755 default:
2757 2756 if (--port->fp_statec_busy != 0) {
2758 2757 /*
2759 2758 * Watch curiously at what the next
2760 2759 * state transition can do.
2761 2760 */
2762 2761 mutex_exit(&port->fp_mutex);
2763 2762 break;
2764 2763 }
2765 2764
2766 2765 FP_TRACE(FP_NHEAD2(9, 0),
2767 2766 "Topology Unknown, Offlining the port..");
2768 2767
2769 2768 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2770 2769 port->fp_state = FC_STATE_OFFLINE;
2771 2770
2772 2771 if (port->fp_offline_tid == NULL) {
2773 2772 port->fp_offline_tid =
2774 2773 timeout(fp_offline_timeout,
2775 2774 (caddr_t)port, fp_offline_ticks);
2776 2775 }
2777 2776 mutex_exit(&port->fp_mutex);
2778 2777 break;
2779 2778 }
2780 2779
2781 2780 mutex_enter(&port->fp_mutex);
2782 2781
2783 2782 port->fp_task = port->fp_last_task;
2784 2783 port->fp_last_task = FP_TASK_IDLE;
2785 2784
2786 2785 mutex_exit(&port->fp_mutex);
2787 2786
2788 2787 fctl_jobdone(job);
2789 2788 break;
2790 2789 }
2791 2790
2792 2791 case JOB_PLOGI_GROUP: {
2793 2792 mutex_exit(&port->fp_mutex);
2794 2793 fp_plogi_group(port, job);
2795 2794 break;
2796 2795 }
2797 2796
2798 2797 case JOB_UNSOL_REQUEST: {
2799 2798 mutex_exit(&port->fp_mutex);
2800 2799 fp_handle_unsol_buf(port,
2801 2800 (fc_unsol_buf_t *)job->job_private, job);
2802 2801 fctl_dealloc_job(job);
2803 2802 break;
2804 2803 }
2805 2804
2806 2805 case JOB_NS_CMD: {
2807 2806 fctl_ns_req_t *ns_cmd;
2808 2807
2809 2808 mutex_exit(&port->fp_mutex);
2810 2809
2811 2810 job->job_flags |= JOB_TYPE_FP_ASYNC;
2812 2811 ns_cmd = (fctl_ns_req_t *)job->job_private;
2813 2812 if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2814 2813 ns_cmd->ns_cmd_code > NS_DA_ID) {
2815 2814 job->job_result = FC_BADCMD;
2816 2815 fctl_jobdone(job);
2817 2816 break;
2818 2817 }
2819 2818
2820 2819 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2821 2820 if (ns_cmd->ns_pd != NULL) {
2822 2821 job->job_result = FC_BADOBJECT;
2823 2822 fctl_jobdone(job);
2824 2823 break;
2825 2824 }
2826 2825
2827 2826 job->job_counter = 1;
2828 2827
2829 2828 rval = fp_ns_reg(port, ns_cmd->ns_pd,
2830 2829 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2831 2830
2832 2831 if (rval != FC_SUCCESS) {
2833 2832 job->job_result = rval;
2834 2833 fctl_jobdone(job);
2835 2834 }
2836 2835 break;
2837 2836 }
2838 2837 job->job_result = FC_SUCCESS;
2839 2838 job->job_counter = 1;
2840 2839
2841 2840 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2842 2841 if (rval != FC_SUCCESS) {
2843 2842 fctl_jobdone(job);
2844 2843 }
2845 2844 break;
2846 2845 }
2847 2846
2848 2847 case JOB_LINK_RESET: {
2849 2848 la_wwn_t *pwwn;
2850 2849 uint32_t topology;
2851 2850
2852 2851 pwwn = (la_wwn_t *)job->job_private;
2853 2852 ASSERT(pwwn != NULL);
2854 2853
2855 2854 topology = port->fp_topology;
2856 2855 mutex_exit(&port->fp_mutex);
2857 2856
2858 2857 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2859 2858 topology == FC_TOP_PRIVATE_LOOP) {
2860 2859 job->job_flags |= JOB_TYPE_FP_ASYNC;
2861 2860 rval = port->fp_fca_tran->fca_reset(
2862 2861 port->fp_fca_handle, FC_FCA_LINK_RESET);
2863 2862 job->job_result = rval;
2864 2863 fp_jobdone(job);
2865 2864 } else {
2866 2865 ASSERT((job->job_flags &
2867 2866 JOB_TYPE_FP_ASYNC) == 0);
2868 2867
2869 2868 if (FC_IS_TOP_SWITCH(topology)) {
2870 2869 rval = fp_remote_lip(port, pwwn,
2871 2870 KM_SLEEP, job);
2872 2871 } else {
2873 2872 rval = FC_FAILURE;
2874 2873 }
2875 2874 if (rval != FC_SUCCESS) {
2876 2875 job->job_result = rval;
2877 2876 }
2878 2877 fctl_jobdone(job);
2879 2878 }
2880 2879 break;
2881 2880 }
2882 2881
2883 2882 default:
2884 2883 mutex_exit(&port->fp_mutex);
2885 2884 job->job_result = FC_BADCMD;
2886 2885 fctl_jobdone(job);
2887 2886 break;
2888 2887 }
2889 2888 }
2890 2889 /* NOTREACHED */
2891 2890 }
2892 2891
2893 2892
2894 2893 /*
2895 2894 * Perform FC port bring up initialization
2896 2895 */
2897 2896 static int
2898 2897 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2899 2898 {
2900 2899 int rval;
2901 2900 uint32_t state;
2902 2901 uint32_t src_id;
2903 2902 fc_lilpmap_t *lilp_map;
2904 2903
2905 2904 ASSERT(MUTEX_HELD(&port->fp_mutex));
2906 2905 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2907 2906
2908 2907 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2909 2908 " port=%p, job=%p", port, job);
2910 2909
2911 2910 port->fp_topology = FC_TOP_UNKNOWN;
2912 2911 port->fp_port_id.port_id = 0;
2913 2912 state = FC_PORT_STATE_MASK(port->fp_state);
2914 2913
2915 2914 if (state == FC_STATE_OFFLINE) {
2916 2915 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2917 2916 job->job_result = FC_OFFLINE;
2918 2917 mutex_exit(&port->fp_mutex);
2919 2918 fctl_jobdone(job);
2920 2919 mutex_enter(&port->fp_mutex);
2921 2920 return (FC_OFFLINE);
2922 2921 }
2923 2922
2924 2923 if (state == FC_STATE_LOOP) {
2925 2924 port->fp_port_type.port_type = FC_NS_PORT_NL;
2926 2925 mutex_exit(&port->fp_mutex);
2927 2926
2928 2927 lilp_map = &port->fp_lilp_map;
2929 2928 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2930 2929 job->job_result = FC_FAILURE;
2931 2930 fctl_jobdone(job);
2932 2931
2933 2932 FP_TRACE(FP_NHEAD1(9, rval),
2934 2933 "LILP map Invalid or not present");
2935 2934 mutex_enter(&port->fp_mutex);
2936 2935 return (FC_FAILURE);
2937 2936 }
2938 2937
2939 2938 if (lilp_map->lilp_length == 0) {
2940 2939 job->job_result = FC_NO_MAP;
2941 2940 fctl_jobdone(job);
2942 2941 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2943 2942 "LILP map length zero");
2944 2943 mutex_enter(&port->fp_mutex);
2945 2944 return (FC_NO_MAP);
2946 2945 }
2947 2946 src_id = lilp_map->lilp_myalpa & 0xFF;
2948 2947 } else {
2949 2948 fc_remote_port_t *pd;
2950 2949 fc_fca_pm_t pm;
2951 2950 fc_fca_p2p_info_t p2p_info;
2952 2951 int pd_recepient;
2953 2952
2954 2953 /*
2955 2954 * Get P2P remote port info if possible
2956 2955 */
2957 2956 bzero((caddr_t)&pm, sizeof (pm));
2958 2957
2959 2958 pm.pm_cmd_flags = FC_FCA_PM_READ;
2960 2959 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2961 2960 pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2962 2961 pm.pm_data_buf = (caddr_t)&p2p_info;
2963 2962
2964 2963 rval = port->fp_fca_tran->fca_port_manage(
2965 2964 port->fp_fca_handle, &pm);
2966 2965
2967 2966 if (rval == FC_SUCCESS) {
2968 2967 port->fp_port_id.port_id = p2p_info.fca_d_id;
2969 2968 port->fp_port_type.port_type = FC_NS_PORT_N;
2970 2969 port->fp_topology = FC_TOP_PT_PT;
2971 2970 port->fp_total_devices = 1;
2972 2971 pd_recepient = fctl_wwn_cmp(
2973 2972 &port->fp_service_params.nport_ww_name,
2974 2973 &p2p_info.pwwn) < 0 ?
2975 2974 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2976 2975 mutex_exit(&port->fp_mutex);
2977 2976 pd = fctl_create_remote_port(port,
2978 2977 &p2p_info.nwwn,
2979 2978 &p2p_info.pwwn,
2980 2979 p2p_info.d_id,
2981 2980 pd_recepient, KM_NOSLEEP);
2982 2981 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2983 2982 " P2P port=%p pd=%p fp %x pd %x", port, pd,
2984 2983 port->fp_port_id.port_id, p2p_info.d_id);
2985 2984 mutex_enter(&port->fp_mutex);
2986 2985 return (FC_SUCCESS);
2987 2986 }
2988 2987 port->fp_port_type.port_type = FC_NS_PORT_N;
2989 2988 mutex_exit(&port->fp_mutex);
2990 2989 src_id = 0;
2991 2990 }
2992 2991
2993 2992 job->job_counter = 1;
2994 2993 job->job_result = FC_SUCCESS;
2995 2994
2996 2995 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2997 2996 KM_SLEEP)) != FC_SUCCESS) {
2998 2997 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2999 2998 job->job_result = FC_FAILURE;
3000 2999 fctl_jobdone(job);
3001 3000
3002 3001 mutex_enter(&port->fp_mutex);
3003 3002 if (port->fp_statec_busy <= 1) {
3004 3003 mutex_exit(&port->fp_mutex);
3005 3004 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
3006 3005 "Couldn't transport FLOGI");
3007 3006 mutex_enter(&port->fp_mutex);
3008 3007 }
3009 3008 return (FC_FAILURE);
3010 3009 }
3011 3010
3012 3011 fp_jobwait(job);
3013 3012
3014 3013 mutex_enter(&port->fp_mutex);
3015 3014 if (job->job_result == FC_SUCCESS) {
3016 3015 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3017 3016 mutex_exit(&port->fp_mutex);
3018 3017 fp_ns_init(port, job, KM_SLEEP);
3019 3018 mutex_enter(&port->fp_mutex);
3020 3019 }
3021 3020 } else {
3022 3021 if (state == FC_STATE_LOOP) {
3023 3022 port->fp_topology = FC_TOP_PRIVATE_LOOP;
3024 3023 port->fp_port_id.port_id =
3025 3024 port->fp_lilp_map.lilp_myalpa & 0xFF;
3026 3025 }
3027 3026 }
3028 3027
3029 3028 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
3030 3029 port, job);
3031 3030
3032 3031 return (FC_SUCCESS);
3033 3032 }
3034 3033
3035 3034
3036 3035 /*
3037 3036 * Perform ULP invocations following FC port startup
3038 3037 */
3039 3038 /* ARGSUSED */
3040 3039 static void
3041 3040 fp_startup_done(opaque_t arg, uchar_t result)
3042 3041 {
3043 3042 fc_local_port_t *port = arg;
3044 3043
3045 3044 fp_attach_ulps(port, FC_CMD_ATTACH);
3046 3045
3047 3046 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
3048 3047 }
3049 3048
3050 3049
3051 3050 /*
3052 3051 * Perform ULP port attach
3053 3052 */
3054 3053 static void
3055 3054 fp_ulp_port_attach(void *arg)
3056 3055 {
3057 3056 fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
3058 3057 fc_local_port_t *port = att->att_port;
3059 3058
3060 3059 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3061 3060 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3062 3061
3063 3062 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3064 3063
3065 3064 if (att->att_need_pm_idle == B_TRUE) {
3066 3065 fctl_idle_port(port);
3067 3066 }
3068 3067
3069 3068 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3070 3069 " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3071 3070
3072 3071 mutex_enter(&att->att_port->fp_mutex);
3073 3072 att->att_port->fp_ulp_attach = 0;
3074 3073
3075 3074 port->fp_task = port->fp_last_task;
3076 3075 port->fp_last_task = FP_TASK_IDLE;
3077 3076
3078 3077 cv_signal(&att->att_port->fp_attach_cv);
3079 3078
3080 3079 mutex_exit(&att->att_port->fp_mutex);
3081 3080
3082 3081 kmem_free(att, sizeof (fp_soft_attach_t));
3083 3082 }
3084 3083
3085 3084 /*
3086 3085 * Entry point to funnel all requests down to FCAs
3087 3086 */
3088 3087 static int
3089 3088 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3090 3089 {
3091 3090 int rval;
3092 3091
3093 3092 mutex_enter(&port->fp_mutex);
3094 3093 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3095 3094 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3096 3095 FC_STATE_OFFLINE))) {
3097 3096 /*
3098 3097 * This means there is more than one state change
3099 3098 * at this point of time - Since they are processed
3100 3099 * serially, any processing of the current one should
3101 3100 * be failed, failed and move up in processing the next
3102 3101 */
3103 3102 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3104 3103 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3105 3104 if (cmd->cmd_job) {
3106 3105 /*
3107 3106 * A state change that is going to be invalidated
3108 3107 * by another one already in the port driver's queue
3109 3108 * need not go up to all ULPs. This will minimize
3110 3109 * needless processing and ripples in ULP modules
3111 3110 */
3112 3111 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3113 3112 }
3114 3113 mutex_exit(&port->fp_mutex);
3115 3114 return (FC_STATEC_BUSY);
3116 3115 }
3117 3116
3118 3117 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3119 3118 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3120 3119 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3121 3120 mutex_exit(&port->fp_mutex);
3122 3121
3123 3122 return (FC_OFFLINE);
3124 3123 }
3125 3124 mutex_exit(&port->fp_mutex);
3126 3125
3127 3126 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3128 3127 if (rval != FC_SUCCESS) {
3129 3128 if (rval == FC_TRAN_BUSY) {
3130 3129 cmd->cmd_retry_interval = fp_retry_delay;
3131 3130 rval = fp_retry_cmd(&cmd->cmd_pkt);
3132 3131 if (rval == FC_FAILURE) {
3133 3132 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3134 3133 }
3135 3134 }
3136 3135 } else {
3137 3136 mutex_enter(&port->fp_mutex);
3138 3137 port->fp_out_fpcmds++;
3139 3138 mutex_exit(&port->fp_mutex);
3140 3139 }
3141 3140
3142 3141 return (rval);
3143 3142 }
3144 3143
3145 3144
3146 3145 /*
3147 3146 * Each time a timeout kicks in, walk the wait queue, decrement the
3148 3147 * the retry_interval, when the retry_interval becomes less than
3149 3148 * or equal to zero, re-transport the command: If the re-transport
3150 3149 * fails with BUSY, enqueue the command in the wait queue.
3151 3150 *
3152 3151 * In order to prevent looping forever because of commands enqueued
3153 3152 * from within this function itself, save the current tail pointer
3154 3153 * (in cur_tail) and exit the loop after serving this command.
3155 3154 */
3156 3155 static void
3157 3156 fp_resendcmd(void *port_handle)
3158 3157 {
3159 3158 int rval;
3160 3159 fc_local_port_t *port;
3161 3160 fp_cmd_t *cmd;
3162 3161 fp_cmd_t *cur_tail;
3163 3162
3164 3163 port = port_handle;
3165 3164 mutex_enter(&port->fp_mutex);
3166 3165 cur_tail = port->fp_wait_tail;
3167 3166 mutex_exit(&port->fp_mutex);
3168 3167
3169 3168 while ((cmd = fp_deque_cmd(port)) != NULL) {
3170 3169 cmd->cmd_retry_interval -= fp_retry_ticker;
3171 3170 /* Check if we are detaching */
3172 3171 if (port->fp_soft_state &
3173 3172 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3174 3173 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3175 3174 cmd->cmd_pkt.pkt_reason = 0;
3176 3175 fp_iodone(cmd);
3177 3176 } else if (cmd->cmd_retry_interval <= 0) {
3178 3177 rval = cmd->cmd_transport(port->fp_fca_handle,
3179 3178 &cmd->cmd_pkt);
3180 3179
3181 3180 if (rval != FC_SUCCESS) {
3182 3181 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3183 3182 if (--cmd->cmd_retry_count) {
3184 3183 fp_enque_cmd(port, cmd);
3185 3184 if (cmd == cur_tail) {
3186 3185 break;
3187 3186 }
3188 3187 continue;
3189 3188 }
3190 3189 cmd->cmd_pkt.pkt_state =
3191 3190 FC_PKT_TRAN_BSY;
3192 3191 } else {
3193 3192 cmd->cmd_pkt.pkt_state =
3194 3193 FC_PKT_TRAN_ERROR;
3195 3194 }
3196 3195 cmd->cmd_pkt.pkt_reason = 0;
3197 3196 fp_iodone(cmd);
3198 3197 } else {
3199 3198 mutex_enter(&port->fp_mutex);
3200 3199 port->fp_out_fpcmds++;
3201 3200 mutex_exit(&port->fp_mutex);
3202 3201 }
3203 3202 } else {
3204 3203 fp_enque_cmd(port, cmd);
3205 3204 }
3206 3205
3207 3206 if (cmd == cur_tail) {
3208 3207 break;
3209 3208 }
3210 3209 }
3211 3210
3212 3211 mutex_enter(&port->fp_mutex);
3213 3212 if (port->fp_wait_head) {
3214 3213 timeout_id_t tid;
3215 3214
3216 3215 mutex_exit(&port->fp_mutex);
3217 3216 tid = timeout(fp_resendcmd, (caddr_t)port,
3218 3217 fp_retry_ticks);
3219 3218 mutex_enter(&port->fp_mutex);
3220 3219 port->fp_wait_tid = tid;
3221 3220 } else {
3222 3221 port->fp_wait_tid = NULL;
3223 3222 }
3224 3223 mutex_exit(&port->fp_mutex);
3225 3224 }
3226 3225
3227 3226
3228 3227 /*
3229 3228 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3230 3229 *
3231 3230 * Yes, as you can see below, cmd_retry_count is used here too. That means
3232 3231 * the retries for BUSY are less if there were transport failures (transport
3233 3232 * failure means fca_transport failure). The goal is not to exceed overall
3234 3233 * retries set in the cmd_retry_count (whatever may be the reason for retry)
3235 3234 *
3236 3235 * Return Values:
3237 3236 * FC_SUCCESS
3238 3237 * FC_FAILURE
3239 3238 */
3240 3239 static int
3241 3240 fp_retry_cmd(fc_packet_t *pkt)
3242 3241 {
3243 3242 fp_cmd_t *cmd;
3244 3243
3245 3244 cmd = pkt->pkt_ulp_private;
3246 3245
3247 3246 if (--cmd->cmd_retry_count) {
3248 3247 fp_enque_cmd(cmd->cmd_port, cmd);
3249 3248 return (FC_SUCCESS);
3250 3249 } else {
3251 3250 return (FC_FAILURE);
3252 3251 }
3253 3252 }
3254 3253
3255 3254
3256 3255 /*
3257 3256 * Queue up FC packet for deferred retry
3258 3257 */
3259 3258 static void
3260 3259 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3261 3260 {
3262 3261 timeout_id_t tid;
3263 3262
3264 3263 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3265 3264
3266 3265 #ifdef DEBUG
3267 3266 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3268 3267 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3269 3268 #endif
3270 3269
3271 3270 mutex_enter(&port->fp_mutex);
3272 3271 if (port->fp_wait_tail) {
3273 3272 port->fp_wait_tail->cmd_next = cmd;
3274 3273 port->fp_wait_tail = cmd;
3275 3274 } else {
3276 3275 ASSERT(port->fp_wait_head == NULL);
3277 3276 port->fp_wait_head = port->fp_wait_tail = cmd;
3278 3277 if (port->fp_wait_tid == NULL) {
3279 3278 mutex_exit(&port->fp_mutex);
3280 3279 tid = timeout(fp_resendcmd, (caddr_t)port,
3281 3280 fp_retry_ticks);
3282 3281 mutex_enter(&port->fp_mutex);
3283 3282 port->fp_wait_tid = tid;
3284 3283 }
3285 3284 }
3286 3285 mutex_exit(&port->fp_mutex);
3287 3286 }
3288 3287
3289 3288
3290 3289 /*
3291 3290 * Handle all RJT codes
3292 3291 */
3293 3292 static int
3294 3293 fp_handle_reject(fc_packet_t *pkt)
3295 3294 {
3296 3295 int rval = FC_FAILURE;
3297 3296 uchar_t next_class;
3298 3297 fp_cmd_t *cmd;
3299 3298 fc_local_port_t *port;
3300 3299
3301 3300 cmd = pkt->pkt_ulp_private;
3302 3301 port = cmd->cmd_port;
3303 3302
3304 3303 switch (pkt->pkt_state) {
3305 3304 case FC_PKT_FABRIC_RJT:
3306 3305 case FC_PKT_NPORT_RJT:
3307 3306 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3308 3307 next_class = fp_get_nextclass(cmd->cmd_port,
3309 3308 FC_TRAN_CLASS(pkt->pkt_tran_flags));
3310 3309
3311 3310 if (next_class == FC_TRAN_CLASS_INVALID) {
3312 3311 return (rval);
3313 3312 }
3314 3313 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3315 3314 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3316 3315
3317 3316 rval = fp_sendcmd(cmd->cmd_port, cmd,
3318 3317 cmd->cmd_port->fp_fca_handle);
3319 3318
3320 3319 if (rval != FC_SUCCESS) {
3321 3320 pkt->pkt_state = FC_PKT_TRAN_ERROR;
3322 3321 }
3323 3322 }
3324 3323 break;
3325 3324
3326 3325 case FC_PKT_LS_RJT:
3327 3326 case FC_PKT_BA_RJT:
3328 3327 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3329 3328 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3330 3329 cmd->cmd_retry_interval = fp_retry_delay;
3331 3330 rval = fp_retry_cmd(pkt);
3332 3331 }
3333 3332 break;
3334 3333
3335 3334 case FC_PKT_FS_RJT:
3336 3335 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
3337 3336 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
3338 3337 (pkt->pkt_expln == 0x00))) {
3339 3338 cmd->cmd_retry_interval = fp_retry_delay;
3340 3339 rval = fp_retry_cmd(pkt);
3341 3340 }
3342 3341 break;
3343 3342
3344 3343 case FC_PKT_LOCAL_RJT:
3345 3344 if (pkt->pkt_reason == FC_REASON_QFULL) {
3346 3345 cmd->cmd_retry_interval = fp_retry_delay;
3347 3346 rval = fp_retry_cmd(pkt);
3348 3347 }
3349 3348 break;
3350 3349
3351 3350 default:
3352 3351 FP_TRACE(FP_NHEAD1(1, 0),
3353 3352 "fp_handle_reject(): Invalid pkt_state");
3354 3353 break;
3355 3354 }
3356 3355
3357 3356 return (rval);
3358 3357 }
3359 3358
3360 3359
3361 3360 /*
3362 3361 * Return the next class of service supported by the FCA
3363 3362 */
3364 3363 static uchar_t
3365 3364 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3366 3365 {
3367 3366 uchar_t next_class;
3368 3367
3369 3368 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3370 3369
3371 3370 switch (cur_class) {
3372 3371 case FC_TRAN_CLASS_INVALID:
3373 3372 if (port->fp_cos & FC_NS_CLASS1) {
3374 3373 next_class = FC_TRAN_CLASS1;
3375 3374 break;
3376 3375 }
3377 3376 /* FALLTHROUGH */
3378 3377
3379 3378 case FC_TRAN_CLASS1:
3380 3379 if (port->fp_cos & FC_NS_CLASS2) {
3381 3380 next_class = FC_TRAN_CLASS2;
3382 3381 break;
3383 3382 }
3384 3383 /* FALLTHROUGH */
3385 3384
3386 3385 case FC_TRAN_CLASS2:
3387 3386 if (port->fp_cos & FC_NS_CLASS3) {
3388 3387 next_class = FC_TRAN_CLASS3;
3389 3388 break;
3390 3389 }
3391 3390 /* FALLTHROUGH */
3392 3391
3393 3392 case FC_TRAN_CLASS3:
3394 3393 default:
3395 3394 next_class = FC_TRAN_CLASS_INVALID;
3396 3395 break;
3397 3396 }
3398 3397
3399 3398 return (next_class);
3400 3399 }
3401 3400
3402 3401
3403 3402 /*
3404 3403 * Determine if a class of service is supported by the FCA
3405 3404 */
3406 3405 static int
3407 3406 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3408 3407 {
3409 3408 int rval;
3410 3409
3411 3410 switch (tran_class) {
3412 3411 case FC_TRAN_CLASS1:
3413 3412 if (cos & FC_NS_CLASS1) {
3414 3413 rval = FC_SUCCESS;
3415 3414 } else {
3416 3415 rval = FC_FAILURE;
3417 3416 }
3418 3417 break;
3419 3418
3420 3419 case FC_TRAN_CLASS2:
3421 3420 if (cos & FC_NS_CLASS2) {
3422 3421 rval = FC_SUCCESS;
3423 3422 } else {
3424 3423 rval = FC_FAILURE;
3425 3424 }
3426 3425 break;
3427 3426
3428 3427 case FC_TRAN_CLASS3:
3429 3428 if (cos & FC_NS_CLASS3) {
3430 3429 rval = FC_SUCCESS;
3431 3430 } else {
3432 3431 rval = FC_FAILURE;
3433 3432 }
3434 3433 break;
3435 3434
3436 3435 default:
3437 3436 rval = FC_FAILURE;
3438 3437 break;
3439 3438 }
3440 3439
3441 3440 return (rval);
3442 3441 }
3443 3442
3444 3443
3445 3444 /*
3446 3445 * Dequeue FC packet for retry
3447 3446 */
3448 3447 static fp_cmd_t *
3449 3448 fp_deque_cmd(fc_local_port_t *port)
3450 3449 {
3451 3450 fp_cmd_t *cmd;
3452 3451
3453 3452 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3454 3453
3455 3454 mutex_enter(&port->fp_mutex);
3456 3455
3457 3456 if (port->fp_wait_head == NULL) {
3458 3457 /*
3459 3458 * To avoid races, NULL the fp_wait_tid as
3460 3459 * we are about to exit the timeout thread.
3461 3460 */
3462 3461 port->fp_wait_tid = NULL;
3463 3462 mutex_exit(&port->fp_mutex);
3464 3463 return (NULL);
3465 3464 }
3466 3465
3467 3466 cmd = port->fp_wait_head;
3468 3467 port->fp_wait_head = cmd->cmd_next;
3469 3468 cmd->cmd_next = NULL;
3470 3469
3471 3470 if (port->fp_wait_head == NULL) {
3472 3471 port->fp_wait_tail = NULL;
3473 3472 }
3474 3473 mutex_exit(&port->fp_mutex);
3475 3474
3476 3475 return (cmd);
3477 3476 }
3478 3477
3479 3478
3480 3479 /*
3481 3480 * Wait for job completion
3482 3481 */
3483 3482 static void
3484 3483 fp_jobwait(job_request_t *job)
3485 3484 {
3486 3485 sema_p(&job->job_port_sema);
3487 3486 }
3488 3487
3489 3488
3490 3489 /*
3491 3490 * Convert FC packet state to FC errno
3492 3491 */
3493 3492 int
3494 3493 fp_state_to_rval(uchar_t state)
3495 3494 {
3496 3495 int count;
3497 3496
3498 3497 for (count = 0; count < sizeof (fp_xlat) /
3499 3498 sizeof (fp_xlat[0]); count++) {
3500 3499 if (fp_xlat[count].xlat_state == state) {
3501 3500 return (fp_xlat[count].xlat_rval);
3502 3501 }
3503 3502 }
3504 3503
3505 3504 return (FC_FAILURE);
3506 3505 }
3507 3506
3508 3507
3509 3508 /*
3510 3509 * For Synchronous I/O requests, the caller is
3511 3510 * expected to do fctl_jobdone(if necessary)
3512 3511 *
3513 3512 * We want to preserve at least one failure in the
3514 3513 * job_result if it happens.
3515 3514 *
3516 3515 */
3517 3516 static void
3518 3517 fp_iodone(fp_cmd_t *cmd)
3519 3518 {
3520 3519 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt;
3521 3520 job_request_t *job = cmd->cmd_job;
3522 3521 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd;
3523 3522
3524 3523 ASSERT(job != NULL);
3525 3524 ASSERT(cmd->cmd_port != NULL);
3526 3525 ASSERT(&cmd->cmd_pkt != NULL);
3527 3526
3528 3527 mutex_enter(&job->job_mutex);
3529 3528 if (job->job_result == FC_SUCCESS) {
3530 3529 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3531 3530 }
3532 3531 mutex_exit(&job->job_mutex);
3533 3532
3534 3533 if (pd) {
3535 3534 mutex_enter(&pd->pd_mutex);
3536 3535 pd->pd_flags = PD_IDLE;
3537 3536 mutex_exit(&pd->pd_mutex);
3538 3537 }
3539 3538
3540 3539 if (ulp_pkt) {
3541 3540 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3542 3541 FP_IS_PKT_ERROR(ulp_pkt)) {
3543 3542 fc_local_port_t *port;
3544 3543 fc_remote_node_t *node;
3545 3544
3546 3545 port = cmd->cmd_port;
3547 3546
3548 3547 mutex_enter(&pd->pd_mutex);
3549 3548 pd->pd_state = PORT_DEVICE_INVALID;
3550 3549 pd->pd_ref_count--;
3551 3550 node = pd->pd_remote_nodep;
3552 3551 mutex_exit(&pd->pd_mutex);
3553 3552
3554 3553 ASSERT(node != NULL);
3555 3554 ASSERT(port != NULL);
3556 3555
3557 3556 if (fctl_destroy_remote_port(port, pd) == 0) {
3558 3557 fctl_destroy_remote_node(node);
3559 3558 }
3560 3559
3561 3560 ulp_pkt->pkt_pd = NULL;
3562 3561 }
3563 3562
3564 3563 ulp_pkt->pkt_comp(ulp_pkt);
3565 3564 }
3566 3565
3567 3566 fp_free_pkt(cmd);
3568 3567 fp_jobdone(job);
3569 3568 }
3570 3569
3571 3570
3572 3571 /*
3573 3572 * Job completion handler
3574 3573 */
3575 3574 static void
3576 3575 fp_jobdone(job_request_t *job)
3577 3576 {
3578 3577 mutex_enter(&job->job_mutex);
3579 3578 ASSERT(job->job_counter > 0);
3580 3579
3581 3580 if (--job->job_counter != 0) {
3582 3581 mutex_exit(&job->job_mutex);
3583 3582 return;
3584 3583 }
3585 3584
3586 3585 if (job->job_ulp_pkts) {
3587 3586 ASSERT(job->job_ulp_listlen > 0);
3588 3587 kmem_free(job->job_ulp_pkts,
3589 3588 sizeof (fc_packet_t *) * job->job_ulp_listlen);
3590 3589 }
3591 3590
3592 3591 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3593 3592 mutex_exit(&job->job_mutex);
3594 3593 fctl_jobdone(job);
3595 3594 } else {
3596 3595 mutex_exit(&job->job_mutex);
3597 3596 sema_v(&job->job_port_sema);
3598 3597 }
3599 3598 }
3600 3599
3601 3600
3602 3601 /*
3603 3602 * Try to perform shutdown of a port during a detach. No return
3604 3603 * value since the detach should not fail because the port shutdown
3605 3604 * failed.
3606 3605 */
3607 3606 static void
3608 3607 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3609 3608 {
3610 3609 int index;
3611 3610 int count;
3612 3611 int flags;
3613 3612 fp_cmd_t *cmd;
3614 3613 struct pwwn_hash *head;
3615 3614 fc_remote_port_t *pd;
3616 3615
3617 3616 ASSERT(MUTEX_HELD(&port->fp_mutex));
3618 3617
3619 3618 job->job_result = FC_SUCCESS;
3620 3619
3621 3620 if (port->fp_taskq) {
3622 3621 /*
3623 3622 * We must release the mutex here to ensure that other
3624 3623 * potential jobs can complete their processing. Many
3625 3624 * also need this mutex.
3626 3625 */
3627 3626 mutex_exit(&port->fp_mutex);
3628 3627 taskq_wait(port->fp_taskq);
3629 3628 mutex_enter(&port->fp_mutex);
3630 3629 }
3631 3630
3632 3631 if (port->fp_offline_tid) {
3633 3632 timeout_id_t tid;
3634 3633
3635 3634 tid = port->fp_offline_tid;
3636 3635 port->fp_offline_tid = NULL;
3637 3636 mutex_exit(&port->fp_mutex);
3638 3637 (void) untimeout(tid);
3639 3638 mutex_enter(&port->fp_mutex);
3640 3639 }
3641 3640
3642 3641 if (port->fp_wait_tid) {
3643 3642 timeout_id_t tid;
3644 3643
3645 3644 tid = port->fp_wait_tid;
3646 3645 port->fp_wait_tid = NULL;
3647 3646 mutex_exit(&port->fp_mutex);
3648 3647 (void) untimeout(tid);
3649 3648 } else {
3650 3649 mutex_exit(&port->fp_mutex);
3651 3650 }
3652 3651
3653 3652 /*
3654 3653 * While we cancel the timeout, let's also return the
3655 3654 * the outstanding requests back to the callers.
3656 3655 */
3657 3656 while ((cmd = fp_deque_cmd(port)) != NULL) {
3658 3657 ASSERT(cmd->cmd_job != NULL);
3659 3658 cmd->cmd_job->job_result = FC_OFFLINE;
3660 3659 fp_iodone(cmd);
3661 3660 }
3662 3661
3663 3662 /*
3664 3663 * Gracefully LOGO with all the devices logged in.
3665 3664 */
3666 3665 mutex_enter(&port->fp_mutex);
3667 3666
3668 3667 for (count = index = 0; index < pwwn_table_size; index++) {
3669 3668 head = &port->fp_pwwn_table[index];
3670 3669 pd = head->pwwn_head;
3671 3670 while (pd != NULL) {
3672 3671 mutex_enter(&pd->pd_mutex);
3673 3672 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3674 3673 count++;
3675 3674 }
3676 3675 mutex_exit(&pd->pd_mutex);
3677 3676 pd = pd->pd_wwn_hnext;
3678 3677 }
3679 3678 }
3680 3679
3681 3680 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3682 3681 flags = job->job_flags;
3683 3682 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3684 3683 } else {
3685 3684 flags = 0;
3686 3685 }
3687 3686 if (count) {
3688 3687 job->job_counter = count;
3689 3688
3690 3689 for (index = 0; index < pwwn_table_size; index++) {
3691 3690 head = &port->fp_pwwn_table[index];
3692 3691 pd = head->pwwn_head;
3693 3692 while (pd != NULL) {
3694 3693 mutex_enter(&pd->pd_mutex);
3695 3694 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3696 3695 ASSERT(pd->pd_login_count > 0);
3697 3696 /*
3698 3697 * Force the counter to ONE in order
3699 3698 * for us to really send LOGO els.
3700 3699 */
3701 3700 pd->pd_login_count = 1;
3702 3701 mutex_exit(&pd->pd_mutex);
3703 3702 mutex_exit(&port->fp_mutex);
3704 3703 (void) fp_logout(port, pd, job);
3705 3704 mutex_enter(&port->fp_mutex);
3706 3705 } else {
3707 3706 mutex_exit(&pd->pd_mutex);
3708 3707 }
3709 3708 pd = pd->pd_wwn_hnext;
3710 3709 }
3711 3710 }
3712 3711 mutex_exit(&port->fp_mutex);
3713 3712 fp_jobwait(job);
3714 3713 } else {
3715 3714 mutex_exit(&port->fp_mutex);
3716 3715 }
3717 3716
3718 3717 if (job->job_result != FC_SUCCESS) {
3719 3718 FP_TRACE(FP_NHEAD1(9, 0),
3720 3719 "Can't logout all devices. Proceeding with"
3721 3720 " port shutdown");
3722 3721 job->job_result = FC_SUCCESS;
3723 3722 }
3724 3723
3725 3724 fctl_destroy_all_remote_ports(port);
3726 3725
3727 3726 mutex_enter(&port->fp_mutex);
3728 3727 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3729 3728 mutex_exit(&port->fp_mutex);
3730 3729 fp_ns_fini(port, job);
3731 3730 } else {
3732 3731 mutex_exit(&port->fp_mutex);
3733 3732 }
3734 3733
3735 3734 if (flags) {
3736 3735 job->job_flags = flags;
3737 3736 }
3738 3737
3739 3738 mutex_enter(&port->fp_mutex);
3740 3739
3741 3740 }
3742 3741
3743 3742
3744 3743 /*
3745 3744 * Build the port driver's data structures based on the AL_PA list
3746 3745 */
3747 3746 static void
3748 3747 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3749 3748 {
3750 3749 int rval;
3751 3750 int flag;
3752 3751 int count;
3753 3752 uint32_t d_id;
3754 3753 fc_remote_port_t *pd;
3755 3754 fc_lilpmap_t *lilp_map;
3756 3755
3757 3756 ASSERT(MUTEX_HELD(&port->fp_mutex));
3758 3757
3759 3758 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3760 3759 job->job_result = FC_OFFLINE;
3761 3760 mutex_exit(&port->fp_mutex);
3762 3761 fp_jobdone(job);
3763 3762 mutex_enter(&port->fp_mutex);
3764 3763 return;
3765 3764 }
3766 3765
3767 3766 if (port->fp_lilp_map.lilp_length == 0) {
3768 3767 mutex_exit(&port->fp_mutex);
3769 3768 job->job_result = FC_NO_MAP;
3770 3769 fp_jobdone(job);
3771 3770 mutex_enter(&port->fp_mutex);
3772 3771 return;
3773 3772 }
3774 3773 mutex_exit(&port->fp_mutex);
3775 3774
3776 3775 lilp_map = &port->fp_lilp_map;
3777 3776 job->job_counter = lilp_map->lilp_length;
3778 3777
3779 3778 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3780 3779 flag = FP_CMD_PLOGI_RETAIN;
3781 3780 } else {
3782 3781 flag = FP_CMD_PLOGI_DONT_CARE;
3783 3782 }
3784 3783
3785 3784 for (count = 0; count < lilp_map->lilp_length; count++) {
3786 3785 d_id = lilp_map->lilp_alpalist[count];
3787 3786
3788 3787 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3789 3788 fp_jobdone(job);
3790 3789 continue;
3791 3790 }
3792 3791
3793 3792 pd = fctl_get_remote_port_by_did(port, d_id);
3794 3793 if (pd) {
3795 3794 mutex_enter(&pd->pd_mutex);
3796 3795 if (flag == FP_CMD_PLOGI_DONT_CARE ||
3797 3796 pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3798 3797 mutex_exit(&pd->pd_mutex);
3799 3798 fp_jobdone(job);
3800 3799 continue;
3801 3800 }
3802 3801 mutex_exit(&pd->pd_mutex);
3803 3802 }
3804 3803
3805 3804 rval = fp_port_login(port, d_id, job, flag,
3806 3805 KM_SLEEP, pd, NULL);
3807 3806 if (rval != FC_SUCCESS) {
3808 3807 fp_jobdone(job);
3809 3808 }
3810 3809 }
3811 3810
3812 3811 mutex_enter(&port->fp_mutex);
3813 3812 }
3814 3813
3815 3814
3816 3815 /*
3817 3816 * Perform loop ONLINE processing
3818 3817 */
3819 3818 static void
3820 3819 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3821 3820 {
3822 3821 int count;
3823 3822 int rval;
3824 3823 uint32_t d_id;
3825 3824 uint32_t listlen;
3826 3825 fc_lilpmap_t *lilp_map;
3827 3826 fc_remote_port_t *pd;
3828 3827 fc_portmap_t *changelist;
3829 3828
3830 3829 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3831 3830
3832 3831 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3833 3832 port, job);
3834 3833
3835 3834 lilp_map = &port->fp_lilp_map;
3836 3835
3837 3836 if (lilp_map->lilp_length) {
3838 3837 mutex_enter(&port->fp_mutex);
3839 3838 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3840 3839 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3841 3840 mutex_exit(&port->fp_mutex);
3842 3841 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3843 3842 } else {
3844 3843 mutex_exit(&port->fp_mutex);
3845 3844 }
3846 3845
3847 3846 job->job_counter = lilp_map->lilp_length;
3848 3847
3849 3848 for (count = 0; count < lilp_map->lilp_length; count++) {
3850 3849 d_id = lilp_map->lilp_alpalist[count];
3851 3850
3852 3851 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3853 3852 fp_jobdone(job);
3854 3853 continue;
3855 3854 }
3856 3855
3857 3856 pd = fctl_get_remote_port_by_did(port, d_id);
3858 3857 if (pd != NULL) {
3859 3858 #ifdef DEBUG
3860 3859 mutex_enter(&pd->pd_mutex);
3861 3860 if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3862 3861 ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3863 3862 }
3864 3863 mutex_exit(&pd->pd_mutex);
3865 3864 #endif
3866 3865 fp_jobdone(job);
3867 3866 continue;
3868 3867 }
3869 3868
3870 3869 rval = fp_port_login(port, d_id, job,
3871 3870 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3872 3871
3873 3872 if (rval != FC_SUCCESS) {
3874 3873 fp_jobdone(job);
3875 3874 }
3876 3875 }
3877 3876 fp_jobwait(job);
3878 3877 }
3879 3878 listlen = 0;
3880 3879 changelist = NULL;
3881 3880
3882 3881 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3883 3882 mutex_enter(&port->fp_mutex);
3884 3883 ASSERT(port->fp_statec_busy > 0);
3885 3884 if (port->fp_statec_busy == 1) {
3886 3885 mutex_exit(&port->fp_mutex);
3887 3886 fctl_fillout_map(port, &changelist, &listlen,
3888 3887 1, 0, orphan);
3889 3888
3890 3889 mutex_enter(&port->fp_mutex);
3891 3890 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3892 3891 ASSERT(port->fp_total_devices == 0);
3893 3892 port->fp_total_devices = port->fp_dev_count;
3894 3893 }
3895 3894 } else {
3896 3895 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3897 3896 }
3898 3897 mutex_exit(&port->fp_mutex);
3899 3898 }
3900 3899
3901 3900 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3902 3901 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3903 3902 listlen, listlen, KM_SLEEP);
3904 3903 } else {
3905 3904 mutex_enter(&port->fp_mutex);
3906 3905 if (--port->fp_statec_busy == 0) {
3907 3906 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3908 3907 }
3909 3908 ASSERT(changelist == NULL && listlen == 0);
3910 3909 mutex_exit(&port->fp_mutex);
3911 3910 }
3912 3911
3913 3912 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3914 3913 port, job);
3915 3914 }
3916 3915
3917 3916
3918 3917 /*
3919 3918 * Get an Arbitrated Loop map from the underlying FCA
3920 3919 */
3921 3920 static int
3922 3921 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3923 3922 {
3924 3923 int rval;
3925 3924
3926 3925 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3927 3926 port, lilp_map);
3928 3927
3929 3928 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3930 3929 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3931 3930 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */
3932 3931
3933 3932 if (rval != FC_SUCCESS) {
3934 3933 rval = FC_NO_MAP;
3935 3934 } else if (lilp_map->lilp_length == 0 &&
3936 3935 (lilp_map->lilp_magic >= MAGIC_LISM &&
3937 3936 lilp_map->lilp_magic < MAGIC_LIRP)) {
3938 3937 uchar_t lilp_length;
3939 3938
3940 3939 /*
3941 3940 * Since the map length is zero, provide all
3942 3941 * the valid AL_PAs for NL_ports discovery.
3943 3942 */
3944 3943 lilp_length = sizeof (fp_valid_alpas) /
3945 3944 sizeof (fp_valid_alpas[0]);
3946 3945 lilp_map->lilp_length = lilp_length;
3947 3946 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3948 3947 lilp_length);
3949 3948 } else {
3950 3949 rval = fp_validate_lilp_map(lilp_map);
3951 3950
3952 3951 if (rval == FC_SUCCESS) {
3953 3952 mutex_enter(&port->fp_mutex);
3954 3953 port->fp_total_devices = lilp_map->lilp_length - 1;
3955 3954 mutex_exit(&port->fp_mutex);
3956 3955 }
3957 3956 }
3958 3957
3959 3958 mutex_enter(&port->fp_mutex);
3960 3959 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3961 3960 port->fp_soft_state |= FP_SOFT_BAD_LINK;
3962 3961 mutex_exit(&port->fp_mutex);
3963 3962
3964 3963 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3965 3964 FC_FCA_RESET_CORE) != FC_SUCCESS) {
3966 3965 FP_TRACE(FP_NHEAD1(9, 0),
3967 3966 "FCA reset failed after LILP map was found"
3968 3967 " to be invalid");
3969 3968 }
3970 3969 } else if (rval == FC_SUCCESS) {
3971 3970 port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3972 3971 mutex_exit(&port->fp_mutex);
3973 3972 } else {
3974 3973 mutex_exit(&port->fp_mutex);
3975 3974 }
3976 3975
3977 3976 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3978 3977 lilp_map);
3979 3978
3980 3979 return (rval);
3981 3980 }
3982 3981
3983 3982
3984 3983 /*
3985 3984 * Perform Fabric Login:
3986 3985 *
3987 3986 * Return Values:
3988 3987 * FC_SUCCESS
3989 3988 * FC_FAILURE
3990 3989 * FC_NOMEM
3991 3990 * FC_TRANSPORT_ERROR
3992 3991 * and a lot others defined in fc_error.h
3993 3992 */
3994 3993 static int
3995 3994 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3996 3995 int flag, int sleep)
3997 3996 {
3998 3997 int rval;
3999 3998 fp_cmd_t *cmd;
4000 3999 uchar_t class;
4001 4000
4002 4001 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4003 4002
4004 4003 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
4005 4004 port, job);
4006 4005
4007 4006 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4008 4007 if (class == FC_TRAN_CLASS_INVALID) {
4009 4008 return (FC_ELS_BAD);
4010 4009 }
4011 4010
4012 4011 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4013 4012 sizeof (la_els_logi_t), sleep, NULL);
4014 4013 if (cmd == NULL) {
4015 4014 return (FC_NOMEM);
4016 4015 }
4017 4016
4018 4017 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4019 4018 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4020 4019 cmd->cmd_flags = flag;
4021 4020 cmd->cmd_retry_count = fp_retry_count;
4022 4021 cmd->cmd_ulp_pkt = NULL;
4023 4022
4024 4023 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
4025 4024 job, LA_ELS_FLOGI);
4026 4025
4027 4026 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
4028 4027 if (rval != FC_SUCCESS) {
4029 4028 fp_free_pkt(cmd);
4030 4029 }
4031 4030
4032 4031 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
4033 4032 port, job);
4034 4033
4035 4034 return (rval);
4036 4035 }
4037 4036
4038 4037
4039 4038 /*
4040 4039 * In some scenarios such as private loop device discovery period
4041 4040 * the fc_remote_port_t data structure isn't allocated. The allocation
4042 4041 * is done when the PLOGI is successful. In some other scenarios
4043 4042 * such as Fabric topology, the fc_remote_port_t is already created
4044 4043 * and initialized with appropriate values (as the NS provides
4045 4044 * them)
4046 4045 */
4047 4046 static int
4048 4047 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
4049 4048 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
4050 4049 {
4051 4050 uchar_t class;
4052 4051 fp_cmd_t *cmd;
4053 4052 uint32_t src_id;
4054 4053 fc_remote_port_t *tmp_pd;
4055 4054 int relogin;
4056 4055 int found = 0;
4057 4056
4058 4057 #ifdef DEBUG
4059 4058 if (pd == NULL) {
4060 4059 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
4061 4060 }
4062 4061 #endif
4063 4062 ASSERT(job->job_counter > 0);
4064 4063
4065 4064 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4066 4065 if (class == FC_TRAN_CLASS_INVALID) {
4067 4066 return (FC_ELS_BAD);
4068 4067 }
4069 4068
4070 4069 mutex_enter(&port->fp_mutex);
4071 4070 tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4072 4071 mutex_exit(&port->fp_mutex);
4073 4072
4074 4073 relogin = 1;
4075 4074 if (tmp_pd) {
4076 4075 mutex_enter(&tmp_pd->pd_mutex);
4077 4076 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4078 4077 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4079 4078 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4080 4079 relogin = 0;
4081 4080 }
4082 4081 mutex_exit(&tmp_pd->pd_mutex);
4083 4082 }
4084 4083
4085 4084 if (!relogin) {
4086 4085 mutex_enter(&tmp_pd->pd_mutex);
4087 4086 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4088 4087 cmd_flag |= FP_CMD_PLOGI_RETAIN;
4089 4088 }
4090 4089 mutex_exit(&tmp_pd->pd_mutex);
4091 4090
4092 4091 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4093 4092 sizeof (la_els_adisc_t), sleep, tmp_pd);
4094 4093 if (cmd == NULL) {
4095 4094 return (FC_NOMEM);
4096 4095 }
4097 4096
4098 4097 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4099 4098 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4100 4099 cmd->cmd_flags = cmd_flag;
4101 4100 cmd->cmd_retry_count = fp_retry_count;
4102 4101 cmd->cmd_ulp_pkt = ulp_pkt;
4103 4102
4104 4103 mutex_enter(&port->fp_mutex);
4105 4104 mutex_enter(&tmp_pd->pd_mutex);
4106 4105 fp_adisc_init(cmd, job);
4107 4106 mutex_exit(&tmp_pd->pd_mutex);
4108 4107 mutex_exit(&port->fp_mutex);
4109 4108
4110 4109 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4111 4110 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4112 4111
4113 4112 } else {
4114 4113 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4115 4114 sizeof (la_els_logi_t), sleep, pd);
4116 4115 if (cmd == NULL) {
4117 4116 return (FC_NOMEM);
4118 4117 }
4119 4118
4120 4119 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4121 4120 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4122 4121 cmd->cmd_flags = cmd_flag;
4123 4122 cmd->cmd_retry_count = fp_retry_count;
4124 4123 cmd->cmd_ulp_pkt = ulp_pkt;
4125 4124
4126 4125 mutex_enter(&port->fp_mutex);
4127 4126 src_id = port->fp_port_id.port_id;
4128 4127 mutex_exit(&port->fp_mutex);
4129 4128
4130 4129 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4131 4130 job, LA_ELS_PLOGI);
4132 4131 }
4133 4132
4134 4133 if (pd) {
4135 4134 mutex_enter(&pd->pd_mutex);
4136 4135 pd->pd_flags = PD_ELS_IN_PROGRESS;
4137 4136 mutex_exit(&pd->pd_mutex);
4138 4137 }
4139 4138
4140 4139 /* npiv check to make sure we don't log into ourself */
4141 4140 if (relogin &&
4142 4141 ((port->fp_npiv_type == FC_NPIV_PORT) ||
4143 4142 (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
4144 4143 if ((d_id & 0xffff00) ==
4145 4144 (port->fp_port_id.port_id & 0xffff00)) {
4146 4145 found = 1;
4147 4146 }
4148 4147 }
4149 4148
4150 4149 if (found ||
4151 4150 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4152 4151 if (found) {
4153 4152 fc_packet_t *pkt = &cmd->cmd_pkt;
4154 4153 pkt->pkt_state = FC_PKT_NPORT_RJT;
4155 4154 }
4156 4155 if (pd) {
4157 4156 mutex_enter(&pd->pd_mutex);
4158 4157 pd->pd_flags = PD_IDLE;
4159 4158 mutex_exit(&pd->pd_mutex);
4160 4159 }
4161 4160
4162 4161 if (ulp_pkt) {
4163 4162 fc_packet_t *pkt = &cmd->cmd_pkt;
4164 4163
4165 4164 ulp_pkt->pkt_state = pkt->pkt_state;
4166 4165 ulp_pkt->pkt_reason = pkt->pkt_reason;
4167 4166 ulp_pkt->pkt_action = pkt->pkt_action;
4168 4167 ulp_pkt->pkt_expln = pkt->pkt_expln;
4169 4168 }
4170 4169
4171 4170 fp_iodone(cmd);
4172 4171 }
4173 4172
4174 4173 return (FC_SUCCESS);
4175 4174 }
4176 4175
4177 4176
4178 4177 /*
4179 4178 * Register the LOGIN parameters with a port device
4180 4179 */
4181 4180 static void
4182 4181 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4183 4182 la_els_logi_t *acc, uchar_t class)
4184 4183 {
4185 4184 fc_remote_node_t *node;
4186 4185
4187 4186 ASSERT(pd != NULL);
4188 4187
4189 4188 mutex_enter(&pd->pd_mutex);
4190 4189 node = pd->pd_remote_nodep;
4191 4190 if (pd->pd_login_count == 0) {
4192 4191 pd->pd_login_count++;
4193 4192 }
4194 4193
4195 4194 if (handle) {
4196 4195 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
4197 4196 (uint8_t *)&acc->common_service,
4198 4197 sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4199 4198 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
4200 4199 (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4201 4200 DDI_DEV_AUTOINCR);
4202 4201 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
4203 4202 (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4204 4203 DDI_DEV_AUTOINCR);
4205 4204 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
4206 4205 (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4207 4206 DDI_DEV_AUTOINCR);
4208 4207 } else {
4209 4208 pd->pd_csp = acc->common_service;
4210 4209 pd->pd_clsp1 = acc->class_1;
4211 4210 pd->pd_clsp2 = acc->class_2;
4212 4211 pd->pd_clsp3 = acc->class_3;
4213 4212 }
4214 4213
4215 4214 pd->pd_state = PORT_DEVICE_LOGGED_IN;
4216 4215 pd->pd_login_class = class;
4217 4216 mutex_exit(&pd->pd_mutex);
4218 4217
4219 4218 #ifndef __lock_lint
4220 4219 ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4221 4220 pd->pd_port_id.port_id) == pd);
4222 4221 #endif
4223 4222
4224 4223 mutex_enter(&node->fd_mutex);
4225 4224 if (handle) {
4226 4225 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
4227 4226 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4228 4227 DDI_DEV_AUTOINCR);
4229 4228 } else {
4230 4229 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4231 4230 }
4232 4231 mutex_exit(&node->fd_mutex);
4233 4232 }
4234 4233
4235 4234
4236 4235 /*
4237 4236 * Mark the remote port as OFFLINE
4238 4237 */
4239 4238 static void
4240 4239 fp_remote_port_offline(fc_remote_port_t *pd)
4241 4240 {
4242 4241 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4243 4242 if (pd->pd_login_count &&
4244 4243 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4245 4244 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4246 4245 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4247 4246 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4248 4247 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4249 4248 pd->pd_login_class = 0;
4250 4249 }
4251 4250 pd->pd_type = PORT_DEVICE_OLD;
4252 4251 pd->pd_flags = PD_IDLE;
4253 4252 fctl_tc_reset(&pd->pd_logo_tc);
4254 4253 }
4255 4254
4256 4255
4257 4256 /*
4258 4257 * Deregistration of a port device
4259 4258 */
4260 4259 static void
4261 4260 fp_unregister_login(fc_remote_port_t *pd)
4262 4261 {
4263 4262 fc_remote_node_t *node;
4264 4263
4265 4264 ASSERT(pd != NULL);
4266 4265
4267 4266 mutex_enter(&pd->pd_mutex);
4268 4267 pd->pd_login_count = 0;
4269 4268 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4270 4269 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4271 4270 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4272 4271 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4273 4272
4274 4273 pd->pd_state = PORT_DEVICE_VALID;
4275 4274 pd->pd_login_class = 0;
4276 4275 node = pd->pd_remote_nodep;
4277 4276 mutex_exit(&pd->pd_mutex);
4278 4277
4279 4278 mutex_enter(&node->fd_mutex);
4280 4279 bzero(node->fd_vv, sizeof (node->fd_vv));
4281 4280 mutex_exit(&node->fd_mutex);
4282 4281 }
4283 4282
4284 4283
4285 4284 /*
4286 4285 * Handle OFFLINE state of an FCA port
4287 4286 */
4288 4287 static void
4289 4288 fp_port_offline(fc_local_port_t *port, int notify)
4290 4289 {
4291 4290 int index;
4292 4291 int statec;
4293 4292 timeout_id_t tid;
4294 4293 struct pwwn_hash *head;
4295 4294 fc_remote_port_t *pd;
4296 4295
4297 4296 ASSERT(MUTEX_HELD(&port->fp_mutex));
4298 4297
4299 4298 for (index = 0; index < pwwn_table_size; index++) {
4300 4299 head = &port->fp_pwwn_table[index];
4301 4300 pd = head->pwwn_head;
4302 4301 while (pd != NULL) {
4303 4302 mutex_enter(&pd->pd_mutex);
4304 4303 fp_remote_port_offline(pd);
4305 4304 fctl_delist_did_table(port, pd);
4306 4305 mutex_exit(&pd->pd_mutex);
4307 4306 pd = pd->pd_wwn_hnext;
4308 4307 }
4309 4308 }
4310 4309 port->fp_total_devices = 0;
4311 4310
4312 4311 statec = 0;
4313 4312 if (notify) {
4314 4313 /*
4315 4314 * Decrement the statec busy counter as we
4316 4315 * are almost done with handling the state
4317 4316 * change
4318 4317 */
4319 4318 ASSERT(port->fp_statec_busy > 0);
4320 4319 if (--port->fp_statec_busy == 0) {
4321 4320 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4322 4321 }
4323 4322 mutex_exit(&port->fp_mutex);
4324 4323 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4325 4324 0, 0, KM_SLEEP);
4326 4325 mutex_enter(&port->fp_mutex);
4327 4326
4328 4327 if (port->fp_statec_busy) {
4329 4328 statec++;
4330 4329 }
4331 4330 } else if (port->fp_statec_busy > 1) {
4332 4331 statec++;
4333 4332 }
4334 4333
4335 4334 if ((tid = port->fp_offline_tid) != NULL) {
4336 4335 mutex_exit(&port->fp_mutex);
4337 4336 (void) untimeout(tid);
4338 4337 mutex_enter(&port->fp_mutex);
4339 4338 }
4340 4339
4341 4340 if (!statec) {
4342 4341 port->fp_offline_tid = timeout(fp_offline_timeout,
4343 4342 (caddr_t)port, fp_offline_ticks);
4344 4343 }
4345 4344 }
4346 4345
4347 4346
4348 4347 /*
4349 4348 * Offline devices and send up a state change notification to ULPs
4350 4349 */
4351 4350 static void
4352 4351 fp_offline_timeout(void *port_handle)
4353 4352 {
4354 4353 int ret;
4355 4354 fc_local_port_t *port = port_handle;
4356 4355 uint32_t listlen = 0;
4357 4356 fc_portmap_t *changelist = NULL;
4358 4357
4359 4358 mutex_enter(&port->fp_mutex);
4360 4359
4361 4360 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4362 4361 (port->fp_soft_state &
4363 4362 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4364 4363 port->fp_dev_count == 0 || port->fp_statec_busy) {
4365 4364 port->fp_offline_tid = NULL;
4366 4365 mutex_exit(&port->fp_mutex);
4367 4366 return;
4368 4367 }
4369 4368
4370 4369 mutex_exit(&port->fp_mutex);
4371 4370
4372 4371 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4373 4372
4374 4373 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4375 4374 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4376 4375 FC_FCA_CORE)) != FC_SUCCESS) {
4377 4376 FP_TRACE(FP_NHEAD1(9, ret),
4378 4377 "Failed to force adapter dump");
4379 4378 } else {
4380 4379 FP_TRACE(FP_NHEAD1(9, 0),
4381 4380 "Forced adapter dump successfully");
4382 4381 }
4383 4382 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4384 4383 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4385 4384 FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4386 4385 FP_TRACE(FP_NHEAD1(9, ret),
4387 4386 "Failed to force adapter dump and reset");
4388 4387 } else {
4389 4388 FP_TRACE(FP_NHEAD1(9, 0),
4390 4389 "Forced adapter dump and reset successfully");
4391 4390 }
4392 4391 }
4393 4392
4394 4393 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4395 4394 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4396 4395 listlen, listlen, KM_SLEEP);
4397 4396
4398 4397 mutex_enter(&port->fp_mutex);
4399 4398 port->fp_offline_tid = NULL;
4400 4399 mutex_exit(&port->fp_mutex);
4401 4400 }
4402 4401
4403 4402
4404 4403 /*
4405 4404 * Perform general purpose ELS request initialization
4406 4405 */
4407 4406 static void
4408 4407 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4409 4408 void (*comp) (), job_request_t *job)
4410 4409 {
4411 4410 fc_packet_t *pkt;
4412 4411
4413 4412 pkt = &cmd->cmd_pkt;
4414 4413 cmd->cmd_job = job;
4415 4414
4416 4415 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4417 4416 pkt->pkt_cmd_fhdr.d_id = d_id;
4418 4417 pkt->pkt_cmd_fhdr.s_id = s_id;
4419 4418 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4420 4419 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4421 4420 pkt->pkt_cmd_fhdr.seq_id = 0;
4422 4421 pkt->pkt_cmd_fhdr.df_ctl = 0;
4423 4422 pkt->pkt_cmd_fhdr.seq_cnt = 0;
4424 4423 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4425 4424 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4426 4425 pkt->pkt_cmd_fhdr.ro = 0;
4427 4426 pkt->pkt_cmd_fhdr.rsvd = 0;
4428 4427 pkt->pkt_comp = comp;
4429 4428 pkt->pkt_timeout = FP_ELS_TIMEOUT;
4430 4429 }
4431 4430
4432 4431
4433 4432 /*
4434 4433 * Initialize PLOGI/FLOGI ELS request
4435 4434 */
4436 4435 static void
4437 4436 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4438 4437 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4439 4438 {
4440 4439 ls_code_t payload;
4441 4440
4442 4441 fp_els_init(cmd, s_id, d_id, intr, job);
4443 4442 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4444 4443
4445 4444 payload.ls_code = ls_code;
4446 4445 payload.mbz = 0;
4447 4446
4448 4447 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
4449 4448 (uint8_t *)&port->fp_service_params,
4450 4449 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4451 4450 DDI_DEV_AUTOINCR);
4452 4451
4453 4452 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4454 4453 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4455 4454 DDI_DEV_AUTOINCR);
4456 4455 }
4457 4456
4458 4457
4459 4458 /*
4460 4459 * Initialize LOGO ELS request
4461 4460 */
4462 4461 static void
4463 4462 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4464 4463 {
4465 4464 fc_local_port_t *port;
4466 4465 fc_packet_t *pkt;
4467 4466 la_els_logo_t payload;
4468 4467
4469 4468 port = pd->pd_port;
4470 4469 pkt = &cmd->cmd_pkt;
4471 4470 ASSERT(MUTEX_HELD(&port->fp_mutex));
4472 4471 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4473 4472
4474 4473 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4475 4474 fp_logo_intr, job);
4476 4475
4477 4476 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4478 4477
4479 4478 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4480 4479 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4481 4480
4482 4481 payload.ls_code.ls_code = LA_ELS_LOGO;
4483 4482 payload.ls_code.mbz = 0;
4484 4483 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4485 4484 payload.nport_id = port->fp_port_id;
4486 4485
4487 4486 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4488 4487 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4489 4488 }
4490 4489
4491 4490 /*
4492 4491 * Initialize RNID ELS request
4493 4492 */
4494 4493 static void
4495 4494 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4496 4495 {
4497 4496 fc_local_port_t *port;
4498 4497 fc_packet_t *pkt;
4499 4498 la_els_rnid_t payload;
4500 4499 fc_remote_port_t *pd;
4501 4500
4502 4501 pkt = &cmd->cmd_pkt;
4503 4502 pd = pkt->pkt_pd;
4504 4503 port = pd->pd_port;
4505 4504
4506 4505 ASSERT(MUTEX_HELD(&port->fp_mutex));
4507 4506 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4508 4507
4509 4508 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4510 4509 fp_rnid_intr, job);
4511 4510
4512 4511 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4513 4512 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4514 4513 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4515 4514
4516 4515 payload.ls_code.ls_code = LA_ELS_RNID;
4517 4516 payload.ls_code.mbz = 0;
4518 4517 payload.data_format = flag;
4519 4518
4520 4519 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4521 4520 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4522 4521 }
4523 4522
4524 4523 /*
4525 4524 * Initialize RLS ELS request
4526 4525 */
4527 4526 static void
4528 4527 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4529 4528 {
4530 4529 fc_local_port_t *port;
4531 4530 fc_packet_t *pkt;
4532 4531 la_els_rls_t payload;
4533 4532 fc_remote_port_t *pd;
4534 4533
4535 4534 pkt = &cmd->cmd_pkt;
4536 4535 pd = pkt->pkt_pd;
4537 4536 port = pd->pd_port;
4538 4537
4539 4538 ASSERT(MUTEX_HELD(&port->fp_mutex));
4540 4539 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4541 4540
4542 4541 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4543 4542 fp_rls_intr, job);
4544 4543
4545 4544 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4546 4545 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4547 4546 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4548 4547
4549 4548 payload.ls_code.ls_code = LA_ELS_RLS;
4550 4549 payload.ls_code.mbz = 0;
4551 4550 payload.rls_portid = port->fp_port_id;
4552 4551
4553 4552 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4554 4553 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4555 4554 }
4556 4555
4557 4556
4558 4557 /*
4559 4558 * Initialize an ADISC ELS request
4560 4559 */
4561 4560 static void
4562 4561 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4563 4562 {
4564 4563 fc_local_port_t *port;
4565 4564 fc_packet_t *pkt;
4566 4565 la_els_adisc_t payload;
4567 4566 fc_remote_port_t *pd;
4568 4567
4569 4568 pkt = &cmd->cmd_pkt;
4570 4569 pd = pkt->pkt_pd;
4571 4570 port = pd->pd_port;
4572 4571
4573 4572 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4574 4573 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4575 4574
4576 4575 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4577 4576 fp_adisc_intr, job);
4578 4577
4579 4578 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4580 4579 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4581 4580 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4582 4581
4583 4582 payload.ls_code.ls_code = LA_ELS_ADISC;
4584 4583 payload.ls_code.mbz = 0;
4585 4584 payload.nport_id = port->fp_port_id;
4586 4585 payload.port_wwn = port->fp_service_params.nport_ww_name;
4587 4586 payload.node_wwn = port->fp_service_params.node_ww_name;
4588 4587 payload.hard_addr = port->fp_hard_addr;
4589 4588
4590 4589 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4591 4590 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4592 4591 }
4593 4592
4594 4593
4595 4594 /*
4596 4595 * Send up a state change notification to ULPs.
4597 4596 * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4598 4597 */
4599 4598 static int
4600 4599 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4601 4600 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4602 4601 {
4603 4602 fc_port_clist_t *clist;
4604 4603 fc_remote_port_t *pd;
4605 4604 int count;
4606 4605
4607 4606 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4608 4607
4609 4608 clist = kmem_zalloc(sizeof (*clist), sleep);
4610 4609 if (clist == NULL) {
4611 4610 kmem_free(changelist, alloc_len * sizeof (*changelist));
4612 4611 return (FC_NOMEM);
4613 4612 }
4614 4613
4615 4614 clist->clist_state = state;
4616 4615
4617 4616 mutex_enter(&port->fp_mutex);
4618 4617 clist->clist_flags = port->fp_topology;
4619 4618 mutex_exit(&port->fp_mutex);
4620 4619
4621 4620 clist->clist_port = (opaque_t)port;
4622 4621 clist->clist_len = listlen;
4623 4622 clist->clist_size = alloc_len;
4624 4623 clist->clist_map = changelist;
4625 4624
4626 4625 /*
4627 4626 * Bump the reference count of each fc_remote_port_t in this changelist.
4628 4627 * This is necessary since these devices will be sitting in a taskq
4629 4628 * and referenced later. When the state change notification is
4630 4629 * complete, the reference counts will be decremented.
4631 4630 */
4632 4631 for (count = 0; count < clist->clist_len; count++) {
4633 4632 pd = clist->clist_map[count].map_pd;
4634 4633
4635 4634 if (pd != NULL) {
4636 4635 mutex_enter(&pd->pd_mutex);
4637 4636 ASSERT((pd->pd_ref_count >= 0) ||
4638 4637 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4639 4638 pd->pd_ref_count++;
4640 4639
4641 4640 if (clist->clist_map[count].map_state !=
4642 4641 PORT_DEVICE_INVALID) {
4643 4642 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4644 4643 }
4645 4644
4646 4645 mutex_exit(&pd->pd_mutex);
4647 4646 }
4648 4647 }
4649 4648
4650 4649 #ifdef DEBUG
4651 4650 /*
4652 4651 * Sanity check for presence of OLD devices in the hash lists
4653 4652 */
4654 4653 if (clist->clist_size) {
4655 4654 ASSERT(clist->clist_map != NULL);
4656 4655 for (count = 0; count < clist->clist_len; count++) {
4657 4656 if (clist->clist_map[count].map_state ==
4658 4657 PORT_DEVICE_INVALID) {
4659 4658 la_wwn_t pwwn;
4660 4659 fc_portid_t d_id;
4661 4660
4662 4661 pd = clist->clist_map[count].map_pd;
4663 4662 ASSERT(pd != NULL);
4664 4663
4665 4664 mutex_enter(&pd->pd_mutex);
4666 4665 pwwn = pd->pd_port_name;
4667 4666 d_id = pd->pd_port_id;
4668 4667 mutex_exit(&pd->pd_mutex);
4669 4668
4670 4669 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4671 4670 ASSERT(pd != clist->clist_map[count].map_pd);
4672 4671
4673 4672 pd = fctl_get_remote_port_by_did(port,
4674 4673 d_id.port_id);
4675 4674 ASSERT(pd != clist->clist_map[count].map_pd);
4676 4675 }
4677 4676 }
4678 4677 }
4679 4678 #endif
4680 4679
4681 4680 mutex_enter(&port->fp_mutex);
4682 4681
4683 4682 if (state == FC_STATE_ONLINE) {
4684 4683 if (--port->fp_statec_busy == 0) {
4685 4684 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4686 4685 }
4687 4686 }
4688 4687 mutex_exit(&port->fp_mutex);
4689 4688
4690 4689 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4691 4690 clist, KM_SLEEP);
4692 4691
4693 4692 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4694 4693 "state=%x, len=%d", port, state, listlen);
4695 4694
4696 4695 return (FC_SUCCESS);
4697 4696 }
4698 4697
4699 4698
4700 4699 /*
4701 4700 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4702 4701 */
4703 4702 static int
4704 4703 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4705 4704 uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4706 4705 {
4707 4706 int ret;
4708 4707 fc_port_clist_t *clist;
4709 4708
4710 4709 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4711 4710
4712 4711 clist = kmem_zalloc(sizeof (*clist), sleep);
4713 4712 if (clist == NULL) {
4714 4713 kmem_free(changelist, alloc_len * sizeof (*changelist));
4715 4714 return (FC_NOMEM);
4716 4715 }
4717 4716
4718 4717 clist->clist_state = FC_STATE_DEVICE_CHANGE;
4719 4718
4720 4719 mutex_enter(&port->fp_mutex);
4721 4720 clist->clist_flags = port->fp_topology;
4722 4721 mutex_exit(&port->fp_mutex);
4723 4722
4724 4723 clist->clist_port = (opaque_t)port;
4725 4724 clist->clist_len = listlen;
4726 4725 clist->clist_size = alloc_len;
4727 4726 clist->clist_map = changelist;
4728 4727
4729 4728 /* Send sysevents for target state changes */
4730 4729
4731 4730 if (clist->clist_size) {
4732 4731 int count;
4733 4732 fc_remote_port_t *pd;
4734 4733
4735 4734 ASSERT(clist->clist_map != NULL);
4736 4735 for (count = 0; count < clist->clist_len; count++) {
4737 4736 pd = clist->clist_map[count].map_pd;
4738 4737
4739 4738 /*
4740 4739 * Bump reference counts on all fc_remote_port_t
4741 4740 * structs in this list. We don't know when the task
4742 4741 * will fire, and we don't need these fc_remote_port_t
4743 4742 * structs going away behind our back.
4744 4743 */
4745 4744 if (pd) {
4746 4745 mutex_enter(&pd->pd_mutex);
4747 4746 ASSERT((pd->pd_ref_count >= 0) ||
4748 4747 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4749 4748 pd->pd_ref_count++;
4750 4749 mutex_exit(&pd->pd_mutex);
4751 4750 }
4752 4751
4753 4752 if (clist->clist_map[count].map_state ==
4754 4753 PORT_DEVICE_VALID) {
4755 4754 if (clist->clist_map[count].map_type ==
4756 4755 PORT_DEVICE_NEW) {
4757 4756 /* Update our state change counter */
4758 4757 mutex_enter(&port->fp_mutex);
4759 4758 port->fp_last_change++;
4760 4759 mutex_exit(&port->fp_mutex);
4761 4760
4762 4761 /* Additions */
4763 4762 fp_log_target_event(port,
4764 4763 ESC_SUNFC_TARGET_ADD,
4765 4764 clist->clist_map[count].map_pwwn,
4766 4765 clist->clist_map[count].map_did.
4767 4766 port_id);
4768 4767 }
4769 4768
4770 4769 } else if ((clist->clist_map[count].map_type ==
4771 4770 PORT_DEVICE_OLD) &&
4772 4771 (clist->clist_map[count].map_state ==
4773 4772 PORT_DEVICE_INVALID)) {
4774 4773 /* Update our state change counter */
4775 4774 mutex_enter(&port->fp_mutex);
4776 4775 port->fp_last_change++;
4777 4776 mutex_exit(&port->fp_mutex);
4778 4777
4779 4778 /*
4780 4779 * For removals, we don't decrement
4781 4780 * pd_ref_count until after the ULP's
4782 4781 * state change callback function has
4783 4782 * completed.
4784 4783 */
4785 4784
4786 4785 /* Removals */
4787 4786 fp_log_target_event(port,
4788 4787 ESC_SUNFC_TARGET_REMOVE,
4789 4788 clist->clist_map[count].map_pwwn,
4790 4789 clist->clist_map[count].map_did.port_id);
4791 4790 }
4792 4791
4793 4792 if (clist->clist_map[count].map_state !=
4794 4793 PORT_DEVICE_INVALID) {
4795 4794 /*
4796 4795 * Indicate that the ULPs are now aware of
4797 4796 * this device.
4798 4797 */
4799 4798
4800 4799 mutex_enter(&pd->pd_mutex);
4801 4800 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4802 4801 mutex_exit(&pd->pd_mutex);
4803 4802 }
4804 4803
4805 4804 #ifdef DEBUG
4806 4805 /*
4807 4806 * Sanity check for OLD devices in the hash lists
4808 4807 */
4809 4808 if (pd && clist->clist_map[count].map_state ==
4810 4809 PORT_DEVICE_INVALID) {
4811 4810 la_wwn_t pwwn;
4812 4811 fc_portid_t d_id;
4813 4812
4814 4813 mutex_enter(&pd->pd_mutex);
4815 4814 pwwn = pd->pd_port_name;
4816 4815 d_id = pd->pd_port_id;
4817 4816 mutex_exit(&pd->pd_mutex);
4818 4817
4819 4818 /*
4820 4819 * This overwrites the 'pd' local variable.
4821 4820 * Beware of this if 'pd' ever gets
4822 4821 * referenced below this block.
4823 4822 */
4824 4823 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4825 4824 ASSERT(pd != clist->clist_map[count].map_pd);
4826 4825
4827 4826 pd = fctl_get_remote_port_by_did(port,
4828 4827 d_id.port_id);
4829 4828 ASSERT(pd != clist->clist_map[count].map_pd);
4830 4829 }
4831 4830 #endif
4832 4831 }
4833 4832 }
4834 4833
4835 4834 if (sync) {
4836 4835 clist->clist_wait = 1;
4837 4836 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4838 4837 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4839 4838 }
4840 4839
4841 4840 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4842 4841 if (sync && ret) {
4843 4842 mutex_enter(&clist->clist_mutex);
4844 4843 while (clist->clist_wait) {
4845 4844 cv_wait(&clist->clist_cv, &clist->clist_mutex);
4846 4845 }
4847 4846 mutex_exit(&clist->clist_mutex);
4848 4847
4849 4848 mutex_destroy(&clist->clist_mutex);
4850 4849 cv_destroy(&clist->clist_cv);
4851 4850 kmem_free(clist, sizeof (*clist));
4852 4851 }
4853 4852
4854 4853 if (!ret) {
4855 4854 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4856 4855 "port=%p", port);
4857 4856 kmem_free(clist->clist_map,
4858 4857 sizeof (*(clist->clist_map)) * clist->clist_size);
4859 4858 kmem_free(clist, sizeof (*clist));
4860 4859 } else {
4861 4860 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4862 4861 port, listlen);
4863 4862 }
4864 4863
4865 4864 return (FC_SUCCESS);
4866 4865 }
4867 4866
4868 4867
4869 4868 /*
4870 4869 * Perform PLOGI to the group of devices for ULPs
4871 4870 */
4872 4871 static void
4873 4872 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4874 4873 {
4875 4874 int offline;
4876 4875 int count;
4877 4876 int rval;
4878 4877 uint32_t listlen;
4879 4878 uint32_t done;
4880 4879 uint32_t d_id;
4881 4880 fc_remote_node_t *node;
4882 4881 fc_remote_port_t *pd;
4883 4882 fc_remote_port_t *tmp_pd;
4884 4883 fc_packet_t *ulp_pkt;
4885 4884 la_els_logi_t *els_data;
4886 4885 ls_code_t ls_code;
4887 4886
4888 4887 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4889 4888 port, job);
4890 4889
4891 4890 done = 0;
4892 4891 listlen = job->job_ulp_listlen;
4893 4892 job->job_counter = job->job_ulp_listlen;
4894 4893
4895 4894 mutex_enter(&port->fp_mutex);
4896 4895 offline = (port->fp_statec_busy ||
4897 4896 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4898 4897 mutex_exit(&port->fp_mutex);
4899 4898
4900 4899 for (count = 0; count < listlen; count++) {
4901 4900 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4902 4901 sizeof (la_els_logi_t));
4903 4902
4904 4903 ulp_pkt = job->job_ulp_pkts[count];
4905 4904 pd = ulp_pkt->pkt_pd;
4906 4905 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4907 4906
4908 4907 if (offline) {
4909 4908 done++;
4910 4909
4911 4910 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4912 4911 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4913 4912 ulp_pkt->pkt_pd = NULL;
4914 4913 ulp_pkt->pkt_comp(ulp_pkt);
4915 4914
4916 4915 job->job_ulp_pkts[count] = NULL;
4917 4916
4918 4917 fp_jobdone(job);
4919 4918 continue;
4920 4919 }
4921 4920
4922 4921 if (pd == NULL) {
4923 4922 pd = fctl_get_remote_port_by_did(port, d_id);
4924 4923 if (pd == NULL) {
4925 4924 /* reset later */
4926 4925 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4927 4926 continue;
4928 4927 }
4929 4928 mutex_enter(&pd->pd_mutex);
4930 4929 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4931 4930 mutex_exit(&pd->pd_mutex);
4932 4931 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4933 4932 done++;
4934 4933 ulp_pkt->pkt_comp(ulp_pkt);
4935 4934 job->job_ulp_pkts[count] = NULL;
4936 4935 fp_jobdone(job);
4937 4936 } else {
4938 4937 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4939 4938 mutex_exit(&pd->pd_mutex);
4940 4939 }
4941 4940 continue;
4942 4941 }
4943 4942
4944 4943 switch (ulp_pkt->pkt_state) {
4945 4944 case FC_PKT_ELS_IN_PROGRESS:
4946 4945 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4947 4946 /* FALLTHRU */
4948 4947 case FC_PKT_LOCAL_RJT:
4949 4948 done++;
4950 4949 ulp_pkt->pkt_comp(ulp_pkt);
4951 4950 job->job_ulp_pkts[count] = NULL;
4952 4951 fp_jobdone(job);
4953 4952 continue;
4954 4953 default:
4955 4954 break;
4956 4955 }
4957 4956
4958 4957 /*
4959 4958 * Validate the pd corresponding to the d_id passed
4960 4959 * by the ULPs
4961 4960 */
4962 4961 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4963 4962 if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4964 4963 done++;
4965 4964 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4966 4965 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4967 4966 ulp_pkt->pkt_pd = NULL;
4968 4967 ulp_pkt->pkt_comp(ulp_pkt);
4969 4968 job->job_ulp_pkts[count] = NULL;
4970 4969 fp_jobdone(job);
4971 4970 continue;
4972 4971 }
4973 4972
4974 4973 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4975 4974 "port=%p, pd=%p", port, pd);
4976 4975
4977 4976 mutex_enter(&pd->pd_mutex);
4978 4977
4979 4978 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4980 4979 done++;
4981 4980 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4982 4981
4983 4982 ls_code.ls_code = LA_ELS_ACC;
4984 4983 ls_code.mbz = 0;
4985 4984
4986 4985 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4987 4986 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4988 4987 sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4989 4988
4990 4989 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4991 4990 (uint8_t *)&pd->pd_csp,
4992 4991 (uint8_t *)&els_data->common_service,
4993 4992 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4994 4993
4995 4994 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4996 4995 (uint8_t *)&pd->pd_port_name,
4997 4996 (uint8_t *)&els_data->nport_ww_name,
4998 4997 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
4999 4998
5000 4999 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5001 5000 (uint8_t *)&pd->pd_clsp1,
5002 5001 (uint8_t *)&els_data->class_1,
5003 5002 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
5004 5003
5005 5004 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5006 5005 (uint8_t *)&pd->pd_clsp2,
5007 5006 (uint8_t *)&els_data->class_2,
5008 5007 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
5009 5008
5010 5009 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5011 5010 (uint8_t *)&pd->pd_clsp3,
5012 5011 (uint8_t *)&els_data->class_3,
5013 5012 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
5014 5013
5015 5014 node = pd->pd_remote_nodep;
5016 5015 pd->pd_login_count++;
5017 5016 pd->pd_flags = PD_IDLE;
5018 5017 ulp_pkt->pkt_pd = pd;
5019 5018 mutex_exit(&pd->pd_mutex);
5020 5019
5021 5020 mutex_enter(&node->fd_mutex);
5022 5021 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5023 5022 (uint8_t *)&node->fd_node_name,
5024 5023 (uint8_t *)(&els_data->node_ww_name),
5025 5024 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
5026 5025
5027 5026 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5028 5027 (uint8_t *)&node->fd_vv,
5029 5028 (uint8_t *)(&els_data->vendor_version),
5030 5029 sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
5031 5030
5032 5031 mutex_exit(&node->fd_mutex);
5033 5032 ulp_pkt->pkt_state = FC_PKT_SUCCESS;
5034 5033 } else {
5035 5034
5036 5035 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
5037 5036 mutex_exit(&pd->pd_mutex);
5038 5037 }
5039 5038
5040 5039 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
5041 5040 ulp_pkt->pkt_comp(ulp_pkt);
5042 5041 job->job_ulp_pkts[count] = NULL;
5043 5042 fp_jobdone(job);
5044 5043 }
5045 5044 }
5046 5045
5047 5046 if (done == listlen) {
5048 5047 fp_jobwait(job);
5049 5048 fctl_jobdone(job);
5050 5049 return;
5051 5050 }
5052 5051
5053 5052 job->job_counter = listlen - done;
5054 5053
5055 5054 for (count = 0; count < listlen; count++) {
5056 5055 int cmd_flags;
5057 5056
5058 5057 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
5059 5058 continue;
5060 5059 }
5061 5060
5062 5061 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
5063 5062
5064 5063 cmd_flags = FP_CMD_PLOGI_RETAIN;
5065 5064
5066 5065 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5067 5066 ASSERT(d_id != 0);
5068 5067
5069 5068 pd = fctl_get_remote_port_by_did(port, d_id);
5070 5069
5071 5070 /*
5072 5071 * We need to properly adjust the port device
5073 5072 * reference counter before we assign the pd
5074 5073 * to the ULP packets port device pointer.
5075 5074 */
5076 5075 if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
5077 5076 mutex_enter(&pd->pd_mutex);
5078 5077 pd->pd_ref_count++;
5079 5078 mutex_exit(&pd->pd_mutex);
5080 5079 FP_TRACE(FP_NHEAD1(3, 0),
5081 5080 "fp_plogi_group: DID = 0x%x using new pd %p \
5082 5081 old pd NULL\n", d_id, pd);
5083 5082 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
5084 5083 ulp_pkt->pkt_pd != pd) {
5085 5084 mutex_enter(&pd->pd_mutex);
5086 5085 pd->pd_ref_count++;
5087 5086 mutex_exit(&pd->pd_mutex);
5088 5087 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5089 5088 ulp_pkt->pkt_pd->pd_ref_count--;
5090 5089 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5091 5090 FP_TRACE(FP_NHEAD1(3, 0),
5092 5091 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
5093 5092 d_id, ulp_pkt->pkt_pd, pd);
5094 5093 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
5095 5094 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5096 5095 ulp_pkt->pkt_pd->pd_ref_count--;
5097 5096 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5098 5097 FP_TRACE(FP_NHEAD1(3, 0),
5099 5098 "fp_plogi_group: DID = 0x%x pd is NULL and \
5100 5099 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
5101 5100 }
5102 5101
5103 5102 ulp_pkt->pkt_pd = pd;
5104 5103
5105 5104 if (pd != NULL) {
5106 5105 mutex_enter(&pd->pd_mutex);
5107 5106 d_id = pd->pd_port_id.port_id;
5108 5107 pd->pd_flags = PD_ELS_IN_PROGRESS;
5109 5108 mutex_exit(&pd->pd_mutex);
5110 5109 } else {
5111 5110 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5112 5111 #ifdef DEBUG
5113 5112 pd = fctl_get_remote_port_by_did(port, d_id);
5114 5113 ASSERT(pd == NULL);
5115 5114 #endif
5116 5115 /*
5117 5116 * In the Fabric topology, use NS to create
5118 5117 * port device, and if that fails still try
5119 5118 * with PLOGI - which will make yet another
5120 5119 * attempt to create after successful PLOGI
5121 5120 */
5122 5121 mutex_enter(&port->fp_mutex);
5123 5122 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5124 5123 mutex_exit(&port->fp_mutex);
5125 5124 pd = fp_create_remote_port_by_ns(port,
5126 5125 d_id, KM_SLEEP);
5127 5126 if (pd) {
5128 5127 cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5129 5128
5130 5129 mutex_enter(&pd->pd_mutex);
5131 5130 pd->pd_flags = PD_ELS_IN_PROGRESS;
5132 5131 mutex_exit(&pd->pd_mutex);
5133 5132
5134 5133 FP_TRACE(FP_NHEAD1(3, 0),
5135 5134 "fp_plogi_group;"
5136 5135 " NS created PD port=%p, job=%p,"
5137 5136 " pd=%p", port, job, pd);
5138 5137 }
5139 5138 } else {
5140 5139 mutex_exit(&port->fp_mutex);
5141 5140 }
5142 5141 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5143 5142 FP_TRACE(FP_NHEAD1(3, 0),
5144 5143 "fp_plogi_group;"
5145 5144 "ulp_pkt's pd is NULL, get a pd %p",
5146 5145 pd);
5147 5146 mutex_enter(&pd->pd_mutex);
5148 5147 pd->pd_ref_count++;
5149 5148 mutex_exit(&pd->pd_mutex);
5150 5149 }
5151 5150 ulp_pkt->pkt_pd = pd;
5152 5151 }
5153 5152
5154 5153 rval = fp_port_login(port, d_id, job, cmd_flags,
5155 5154 KM_SLEEP, pd, ulp_pkt);
5156 5155
5157 5156 if (rval == FC_SUCCESS) {
5158 5157 continue;
5159 5158 }
5160 5159
5161 5160 if (rval == FC_STATEC_BUSY) {
5162 5161 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5163 5162 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5164 5163 } else {
5165 5164 ulp_pkt->pkt_state = FC_PKT_FAILURE;
5166 5165 }
5167 5166
5168 5167 if (pd) {
5169 5168 mutex_enter(&pd->pd_mutex);
5170 5169 pd->pd_flags = PD_IDLE;
5171 5170 mutex_exit(&pd->pd_mutex);
5172 5171 }
5173 5172
5174 5173 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5175 5174 ASSERT(pd != NULL);
5176 5175
5177 5176 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5178 5177 " PD removed; port=%p, job=%p", port, job);
5179 5178
5180 5179 mutex_enter(&pd->pd_mutex);
5181 5180 pd->pd_ref_count--;
5182 5181 node = pd->pd_remote_nodep;
5183 5182 mutex_exit(&pd->pd_mutex);
5184 5183
5185 5184 ASSERT(node != NULL);
5186 5185
5187 5186 if (fctl_destroy_remote_port(port, pd) == 0) {
5188 5187 fctl_destroy_remote_node(node);
5189 5188 }
5190 5189 ulp_pkt->pkt_pd = NULL;
5191 5190 }
5192 5191 ulp_pkt->pkt_comp(ulp_pkt);
5193 5192 fp_jobdone(job);
5194 5193 }
5195 5194
5196 5195 fp_jobwait(job);
5197 5196 fctl_jobdone(job);
5198 5197
5199 5198 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5200 5199 port, job);
5201 5200 }
5202 5201
5203 5202
5204 5203 /*
5205 5204 * Name server request initialization
5206 5205 */
5207 5206 static void
5208 5207 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5209 5208 {
5210 5209 int rval;
5211 5210 int count;
5212 5211 int size;
5213 5212
5214 5213 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5215 5214
5216 5215 job->job_counter = 1;
5217 5216 job->job_result = FC_SUCCESS;
5218 5217
5219 5218 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5220 5219 KM_SLEEP, NULL, NULL);
5221 5220
5222 5221 if (rval != FC_SUCCESS) {
5223 5222 mutex_enter(&port->fp_mutex);
5224 5223 port->fp_topology = FC_TOP_NO_NS;
5225 5224 mutex_exit(&port->fp_mutex);
5226 5225 return;
5227 5226 }
5228 5227
5229 5228 fp_jobwait(job);
5230 5229
5231 5230 if (job->job_result != FC_SUCCESS) {
5232 5231 mutex_enter(&port->fp_mutex);
5233 5232 port->fp_topology = FC_TOP_NO_NS;
5234 5233 mutex_exit(&port->fp_mutex);
5235 5234 return;
5236 5235 }
5237 5236
5238 5237 /*
5239 5238 * At this time, we'll do NS registration for objects in the
5240 5239 * ns_reg_cmds (see top of this file) array.
5241 5240 *
5242 5241 * Each time a ULP module registers with the transport, the
5243 5242 * appropriate fc4 bit is set fc4 types and registered with
5244 5243 * the NS for this support. Also, ULPs and FC admin utilities
5245 5244 * may do registration for objects like IP address, symbolic
5246 5245 * port/node name, Initial process associator at run time.
5247 5246 */
5248 5247 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5249 5248 job->job_counter = size;
5250 5249 job->job_result = FC_SUCCESS;
5251 5250
5252 5251 for (count = 0; count < size; count++) {
5253 5252 if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5254 5253 job, 0, sleep) != FC_SUCCESS) {
5255 5254 fp_jobdone(job);
5256 5255 }
5257 5256 }
5258 5257 if (size) {
5259 5258 fp_jobwait(job);
5260 5259 }
5261 5260
5262 5261 job->job_result = FC_SUCCESS;
5263 5262
5264 5263 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5265 5264
5266 5265 if (port->fp_dev_count < FP_MAX_DEVICES) {
5267 5266 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5268 5267 }
5269 5268
5270 5269 job->job_counter = 1;
5271 5270
5272 5271 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5273 5272 sleep) == FC_SUCCESS) {
5274 5273 fp_jobwait(job);
5275 5274 }
5276 5275 }
5277 5276
5278 5277
5279 5278 /*
5280 5279 * Name server finish:
5281 5280 * Unregister for RSCNs
5282 5281 * Unregister all the host port objects in the Name Server
5283 5282 * Perform LOGO with the NS;
5284 5283 */
5285 5284 static void
5286 5285 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5287 5286 {
5288 5287 fp_cmd_t *cmd;
5289 5288 uchar_t class;
5290 5289 uint32_t s_id;
5291 5290 fc_packet_t *pkt;
5292 5291 la_els_logo_t payload;
5293 5292
5294 5293 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5295 5294
5296 5295 job->job_counter = 1;
5297 5296
5298 5297 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5299 5298 FC_SUCCESS) {
5300 5299 fp_jobdone(job);
5301 5300 }
5302 5301 fp_jobwait(job);
5303 5302
5304 5303 job->job_counter = 1;
5305 5304
5306 5305 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5307 5306 fp_jobdone(job);
5308 5307 }
5309 5308 fp_jobwait(job);
5310 5309
5311 5310 job->job_counter = 1;
5312 5311
5313 5312 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5314 5313 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5315 5314 pkt = &cmd->cmd_pkt;
5316 5315
5317 5316 mutex_enter(&port->fp_mutex);
5318 5317 class = port->fp_ns_login_class;
5319 5318 s_id = port->fp_port_id.port_id;
5320 5319 payload.nport_id = port->fp_port_id;
5321 5320 mutex_exit(&port->fp_mutex);
5322 5321
5323 5322 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5324 5323 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5325 5324 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5326 5325 cmd->cmd_retry_count = 1;
5327 5326 cmd->cmd_ulp_pkt = NULL;
5328 5327
5329 5328 if (port->fp_npiv_type == FC_NPIV_PORT) {
5330 5329 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5331 5330 } else {
5332 5331 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5333 5332 }
5334 5333
5335 5334 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5336 5335
5337 5336 payload.ls_code.ls_code = LA_ELS_LOGO;
5338 5337 payload.ls_code.mbz = 0;
5339 5338 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5340 5339
5341 5340 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
5342 5341 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5343 5342
5344 5343 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5345 5344 fp_iodone(cmd);
5346 5345 }
5347 5346 fp_jobwait(job);
5348 5347 }
5349 5348
5350 5349
5351 5350 /*
5352 5351 * NS Registration function.
5353 5352 *
5354 5353 * It should be seriously noted that FC-GS-2 currently doesn't support
5355 5354 * an Object Registration by a D_ID other than the owner of the object.
5356 5355 * What we are aiming at currently is to at least allow Symbolic Node/Port
5357 5356 * Name registration for any N_Port Identifier by the host software.
5358 5357 *
5359 5358 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5360 5359 * function treats the request as Host NS Object.
5361 5360 */
5362 5361 static int
5363 5362 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5364 5363 job_request_t *job, int polled, int sleep)
5365 5364 {
5366 5365 int rval;
5367 5366 fc_portid_t s_id;
5368 5367 fc_packet_t *pkt;
5369 5368 fp_cmd_t *cmd;
5370 5369
5371 5370 if (pd == NULL) {
5372 5371 mutex_enter(&port->fp_mutex);
5373 5372 s_id = port->fp_port_id;
5374 5373 mutex_exit(&port->fp_mutex);
5375 5374 } else {
5376 5375 mutex_enter(&pd->pd_mutex);
5377 5376 s_id = pd->pd_port_id;
5378 5377 mutex_exit(&pd->pd_mutex);
5379 5378 }
5380 5379
5381 5380 if (polled) {
5382 5381 job->job_counter = 1;
5383 5382 }
5384 5383
5385 5384 switch (cmd_code) {
5386 5385 case NS_RPN_ID:
5387 5386 case NS_RNN_ID: {
5388 5387 ns_rxn_req_t rxn;
5389 5388
5390 5389 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5391 5390 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5392 5391 if (cmd == NULL) {
5393 5392 return (FC_NOMEM);
5394 5393 }
5395 5394 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5396 5395 pkt = &cmd->cmd_pkt;
5397 5396
5398 5397 if (pd == NULL) {
5399 5398 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
5400 5399 (port->fp_service_params.nport_ww_name) :
5401 5400 (port->fp_service_params.node_ww_name));
5402 5401 } else {
5403 5402 if (cmd_code == NS_RPN_ID) {
5404 5403 mutex_enter(&pd->pd_mutex);
5405 5404 rxn.rxn_xname = pd->pd_port_name;
5406 5405 mutex_exit(&pd->pd_mutex);
5407 5406 } else {
5408 5407 fc_remote_node_t *node;
5409 5408
5410 5409 mutex_enter(&pd->pd_mutex);
5411 5410 node = pd->pd_remote_nodep;
5412 5411 mutex_exit(&pd->pd_mutex);
5413 5412
5414 5413 mutex_enter(&node->fd_mutex);
5415 5414 rxn.rxn_xname = node->fd_node_name;
5416 5415 mutex_exit(&node->fd_mutex);
5417 5416 }
5418 5417 }
5419 5418 rxn.rxn_port_id = s_id;
5420 5419
5421 5420 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5422 5421 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5423 5422 sizeof (rxn), DDI_DEV_AUTOINCR);
5424 5423
5425 5424 break;
5426 5425 }
5427 5426
5428 5427 case NS_RCS_ID: {
5429 5428 ns_rcos_t rcos;
5430 5429
5431 5430 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5432 5431 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5433 5432 if (cmd == NULL) {
5434 5433 return (FC_NOMEM);
5435 5434 }
5436 5435 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5437 5436 pkt = &cmd->cmd_pkt;
5438 5437
5439 5438 if (pd == NULL) {
5440 5439 rcos.rcos_cos = port->fp_cos;
5441 5440 } else {
5442 5441 mutex_enter(&pd->pd_mutex);
5443 5442 rcos.rcos_cos = pd->pd_cos;
5444 5443 mutex_exit(&pd->pd_mutex);
5445 5444 }
5446 5445 rcos.rcos_port_id = s_id;
5447 5446
5448 5447 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5449 5448 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5450 5449 sizeof (rcos), DDI_DEV_AUTOINCR);
5451 5450
5452 5451 break;
5453 5452 }
5454 5453
5455 5454 case NS_RFT_ID: {
5456 5455 ns_rfc_type_t rfc;
5457 5456
5458 5457 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5459 5458 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5460 5459 NULL);
5461 5460 if (cmd == NULL) {
5462 5461 return (FC_NOMEM);
5463 5462 }
5464 5463 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5465 5464 pkt = &cmd->cmd_pkt;
5466 5465
5467 5466 if (pd == NULL) {
5468 5467 mutex_enter(&port->fp_mutex);
5469 5468 bcopy(port->fp_fc4_types, rfc.rfc_types,
5470 5469 sizeof (port->fp_fc4_types));
5471 5470 mutex_exit(&port->fp_mutex);
5472 5471 } else {
5473 5472 mutex_enter(&pd->pd_mutex);
5474 5473 bcopy(pd->pd_fc4types, rfc.rfc_types,
5475 5474 sizeof (pd->pd_fc4types));
5476 5475 mutex_exit(&pd->pd_mutex);
5477 5476 }
5478 5477 rfc.rfc_port_id = s_id;
5479 5478
5480 5479 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5481 5480 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5482 5481 sizeof (rfc), DDI_DEV_AUTOINCR);
5483 5482
5484 5483 break;
5485 5484 }
5486 5485
5487 5486 case NS_RSPN_ID: {
5488 5487 uchar_t name_len;
5489 5488 int pl_size;
5490 5489 fc_portid_t spn;
5491 5490
5492 5491 if (pd == NULL) {
5493 5492 mutex_enter(&port->fp_mutex);
5494 5493 name_len = port->fp_sym_port_namelen;
5495 5494 mutex_exit(&port->fp_mutex);
5496 5495 } else {
5497 5496 mutex_enter(&pd->pd_mutex);
5498 5497 name_len = pd->pd_spn_len;
5499 5498 mutex_exit(&pd->pd_mutex);
5500 5499 }
5501 5500
5502 5501 pl_size = sizeof (fc_portid_t) + name_len + 1;
5503 5502
5504 5503 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5505 5504 sizeof (fc_reg_resp_t), sleep, NULL);
5506 5505 if (cmd == NULL) {
5507 5506 return (FC_NOMEM);
5508 5507 }
5509 5508
5510 5509 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5511 5510
5512 5511 pkt = &cmd->cmd_pkt;
5513 5512
5514 5513 spn = s_id;
5515 5514
5516 5515 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5517 5516 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5518 5517 DDI_DEV_AUTOINCR);
5519 5518 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5520 5519 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5521 5520 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5522 5521
5523 5522 if (pd == NULL) {
5524 5523 mutex_enter(&port->fp_mutex);
5525 5524 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5526 5525 (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5527 5526 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5528 5527 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5529 5528 mutex_exit(&port->fp_mutex);
5530 5529 } else {
5531 5530 mutex_enter(&pd->pd_mutex);
5532 5531 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5533 5532 (uint8_t *)pd->pd_spn,
5534 5533 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5535 5534 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5536 5535 mutex_exit(&pd->pd_mutex);
5537 5536 }
5538 5537 break;
5539 5538 }
5540 5539
5541 5540 case NS_RPT_ID: {
5542 5541 ns_rpt_t rpt;
5543 5542
5544 5543 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5545 5544 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5546 5545 if (cmd == NULL) {
5547 5546 return (FC_NOMEM);
5548 5547 }
5549 5548 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5550 5549 pkt = &cmd->cmd_pkt;
5551 5550
5552 5551 if (pd == NULL) {
5553 5552 rpt.rpt_type = port->fp_port_type;
5554 5553 } else {
5555 5554 mutex_enter(&pd->pd_mutex);
5556 5555 rpt.rpt_type = pd->pd_porttype;
5557 5556 mutex_exit(&pd->pd_mutex);
5558 5557 }
5559 5558 rpt.rpt_port_id = s_id;
5560 5559
5561 5560 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5562 5561 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5563 5562 sizeof (rpt), DDI_DEV_AUTOINCR);
5564 5563
5565 5564 break;
5566 5565 }
5567 5566
5568 5567 case NS_RIP_NN: {
5569 5568 ns_rip_t rip;
5570 5569
5571 5570 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5572 5571 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5573 5572 if (cmd == NULL) {
5574 5573 return (FC_NOMEM);
5575 5574 }
5576 5575 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5577 5576 pkt = &cmd->cmd_pkt;
5578 5577
5579 5578 if (pd == NULL) {
5580 5579 rip.rip_node_name =
5581 5580 port->fp_service_params.node_ww_name;
5582 5581 bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5583 5582 sizeof (port->fp_ip_addr));
5584 5583 } else {
5585 5584 fc_remote_node_t *node;
5586 5585
5587 5586 /*
5588 5587 * The most correct implementation should have the IP
5589 5588 * address in the fc_remote_node_t structure; I believe
5590 5589 * Node WWN and IP address should have one to one
5591 5590 * correlation (but guess what this is changing in
5592 5591 * FC-GS-2 latest draft)
5593 5592 */
5594 5593 mutex_enter(&pd->pd_mutex);
5595 5594 node = pd->pd_remote_nodep;
5596 5595 bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5597 5596 sizeof (pd->pd_ip_addr));
5598 5597 mutex_exit(&pd->pd_mutex);
5599 5598
5600 5599 mutex_enter(&node->fd_mutex);
5601 5600 rip.rip_node_name = node->fd_node_name;
5602 5601 mutex_exit(&node->fd_mutex);
5603 5602 }
5604 5603
5605 5604 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
5606 5605 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5607 5606 sizeof (rip), DDI_DEV_AUTOINCR);
5608 5607
5609 5608 break;
5610 5609 }
5611 5610
5612 5611 case NS_RIPA_NN: {
5613 5612 ns_ipa_t ipa;
5614 5613
5615 5614 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5616 5615 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5617 5616 if (cmd == NULL) {
5618 5617 return (FC_NOMEM);
5619 5618 }
5620 5619 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5621 5620 pkt = &cmd->cmd_pkt;
5622 5621
5623 5622 if (pd == NULL) {
5624 5623 ipa.ipa_node_name =
5625 5624 port->fp_service_params.node_ww_name;
5626 5625 bcopy(port->fp_ipa, ipa.ipa_value,
5627 5626 sizeof (port->fp_ipa));
5628 5627 } else {
5629 5628 fc_remote_node_t *node;
5630 5629
5631 5630 mutex_enter(&pd->pd_mutex);
5632 5631 node = pd->pd_remote_nodep;
5633 5632 mutex_exit(&pd->pd_mutex);
5634 5633
5635 5634 mutex_enter(&node->fd_mutex);
5636 5635 ipa.ipa_node_name = node->fd_node_name;
5637 5636 bcopy(node->fd_ipa, ipa.ipa_value,
5638 5637 sizeof (node->fd_ipa));
5639 5638 mutex_exit(&node->fd_mutex);
5640 5639 }
5641 5640
5642 5641 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5643 5642 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5644 5643 sizeof (ipa), DDI_DEV_AUTOINCR);
5645 5644
5646 5645 break;
5647 5646 }
5648 5647
5649 5648 case NS_RSNN_NN: {
5650 5649 uchar_t name_len;
5651 5650 int pl_size;
5652 5651 la_wwn_t snn;
5653 5652 fc_remote_node_t *node = NULL;
5654 5653
5655 5654 if (pd == NULL) {
5656 5655 mutex_enter(&port->fp_mutex);
5657 5656 name_len = port->fp_sym_node_namelen;
5658 5657 mutex_exit(&port->fp_mutex);
5659 5658 } else {
5660 5659 mutex_enter(&pd->pd_mutex);
5661 5660 node = pd->pd_remote_nodep;
5662 5661 mutex_exit(&pd->pd_mutex);
5663 5662
5664 5663 mutex_enter(&node->fd_mutex);
5665 5664 name_len = node->fd_snn_len;
5666 5665 mutex_exit(&node->fd_mutex);
5667 5666 }
5668 5667
5669 5668 pl_size = sizeof (la_wwn_t) + name_len + 1;
5670 5669
5671 5670 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5672 5671 pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5673 5672 if (cmd == NULL) {
5674 5673 return (FC_NOMEM);
5675 5674 }
5676 5675 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5677 5676
5678 5677 pkt = &cmd->cmd_pkt;
5679 5678
5680 5679 bcopy(&port->fp_service_params.node_ww_name,
5681 5680 &snn, sizeof (la_wwn_t));
5682 5681
5683 5682 if (pd == NULL) {
5684 5683 mutex_enter(&port->fp_mutex);
5685 5684 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5686 5685 (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5687 5686 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5688 5687 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5689 5688 mutex_exit(&port->fp_mutex);
5690 5689 } else {
5691 5690 ASSERT(node != NULL);
5692 5691 mutex_enter(&node->fd_mutex);
5693 5692 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5694 5693 (uint8_t *)node->fd_snn,
5695 5694 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5696 5695 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5697 5696 mutex_exit(&node->fd_mutex);
5698 5697 }
5699 5698
5700 5699 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
5701 5700 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5702 5701 sizeof (snn), DDI_DEV_AUTOINCR);
5703 5702 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5704 5703 (uint8_t *)(pkt->pkt_cmd
5705 5704 + sizeof (fc_ct_header_t) + sizeof (snn)),
5706 5705 1, DDI_DEV_AUTOINCR);
5707 5706
5708 5707 break;
5709 5708 }
5710 5709
5711 5710 case NS_DA_ID: {
5712 5711 ns_remall_t rall;
5713 5712 char tmp[4] = {0};
5714 5713 char *ptr;
5715 5714
5716 5715 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5717 5716 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5718 5717
5719 5718 if (cmd == NULL) {
5720 5719 return (FC_NOMEM);
5721 5720 }
5722 5721
5723 5722 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5724 5723 pkt = &cmd->cmd_pkt;
5725 5724
5726 5725 ptr = (char *)(&s_id);
5727 5726 tmp[3] = *ptr++;
5728 5727 tmp[2] = *ptr++;
5729 5728 tmp[1] = *ptr++;
5730 5729 tmp[0] = *ptr;
5731 5730 #if defined(_BIT_FIELDS_LTOH)
5732 5731 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5733 5732 #else
5734 5733 rall.rem_port_id = s_id;
5735 5734 #endif
5736 5735 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
5737 5736 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5738 5737 sizeof (rall), DDI_DEV_AUTOINCR);
5739 5738
5740 5739 break;
5741 5740 }
5742 5741
5743 5742 default:
5744 5743 return (FC_FAILURE);
5745 5744 }
5746 5745
5747 5746 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5748 5747
5749 5748 if (rval != FC_SUCCESS) {
5750 5749 job->job_result = rval;
5751 5750 fp_iodone(cmd);
5752 5751 }
5753 5752
5754 5753 if (polled) {
5755 5754 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5756 5755 fp_jobwait(job);
5757 5756 } else {
5758 5757 rval = FC_SUCCESS;
5759 5758 }
5760 5759
5761 5760 return (rval);
5762 5761 }
5763 5762
5764 5763
5765 5764 /*
5766 5765 * Common interrupt handler
5767 5766 */
5768 5767 static int
5769 5768 fp_common_intr(fc_packet_t *pkt, int iodone)
5770 5769 {
5771 5770 int rval = FC_FAILURE;
5772 5771 fp_cmd_t *cmd;
5773 5772 fc_local_port_t *port;
5774 5773
5775 5774 cmd = pkt->pkt_ulp_private;
5776 5775 port = cmd->cmd_port;
5777 5776
5778 5777 /*
5779 5778 * Fail fast the upper layer requests if
5780 5779 * a state change has occurred amidst.
5781 5780 */
5782 5781 mutex_enter(&port->fp_mutex);
5783 5782 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5784 5783 mutex_exit(&port->fp_mutex);
5785 5784 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5786 5785 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5787 5786 } else if (!(port->fp_soft_state &
5788 5787 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5789 5788 mutex_exit(&port->fp_mutex);
5790 5789
5791 5790 switch (pkt->pkt_state) {
5792 5791 case FC_PKT_LOCAL_BSY:
5793 5792 case FC_PKT_FABRIC_BSY:
5794 5793 case FC_PKT_NPORT_BSY:
5795 5794 case FC_PKT_TIMEOUT:
5796 5795 cmd->cmd_retry_interval = (pkt->pkt_state ==
5797 5796 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5798 5797 rval = fp_retry_cmd(pkt);
5799 5798 break;
5800 5799
5801 5800 case FC_PKT_FABRIC_RJT:
5802 5801 case FC_PKT_NPORT_RJT:
5803 5802 case FC_PKT_LOCAL_RJT:
5804 5803 case FC_PKT_LS_RJT:
5805 5804 case FC_PKT_FS_RJT:
5806 5805 case FC_PKT_BA_RJT:
5807 5806 rval = fp_handle_reject(pkt);
5808 5807 break;
5809 5808
5810 5809 default:
5811 5810 if (pkt->pkt_resp_resid) {
5812 5811 cmd->cmd_retry_interval = 0;
5813 5812 rval = fp_retry_cmd(pkt);
5814 5813 }
5815 5814 break;
5816 5815 }
5817 5816 } else {
5818 5817 mutex_exit(&port->fp_mutex);
5819 5818 }
5820 5819
5821 5820 if (rval != FC_SUCCESS && iodone) {
5822 5821 fp_iodone(cmd);
5823 5822 rval = FC_SUCCESS;
5824 5823 }
5825 5824
5826 5825 return (rval);
5827 5826 }
5828 5827
5829 5828
5830 5829 /*
5831 5830 * Some not so long winding theory on point to point topology:
5832 5831 *
5833 5832 * In the ACC payload, if the D_ID is ZERO and the common service
5834 5833 * parameters indicate N_Port, then the topology is POINT TO POINT.
5835 5834 *
5836 5835 * In a point to point topology with an N_Port, during Fabric Login,
5837 5836 * the destination N_Port will check with our WWN and decide if it
5838 5837 * needs to issue PLOGI or not. That means, FLOGI could potentially
5839 5838 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5840 5839 * PLOGI creates the device handles.
5841 5840 *
5842 5841 * Assuming that the host port WWN is greater than the other N_Port
5843 5842 * WWN, then we become the master (be aware that this isn't the word
5844 5843 * used in the FC standards) and initiate the PLOGI.
5845 5844 *
5846 5845 */
5847 5846 static void
5848 5847 fp_flogi_intr(fc_packet_t *pkt)
5849 5848 {
5850 5849 int state;
5851 5850 int f_port;
5852 5851 uint32_t s_id;
5853 5852 uint32_t d_id;
5854 5853 fp_cmd_t *cmd;
5855 5854 fc_local_port_t *port;
5856 5855 la_wwn_t *swwn;
5857 5856 la_wwn_t dwwn;
5858 5857 la_wwn_t nwwn;
5859 5858 fc_remote_port_t *pd;
5860 5859 la_els_logi_t *acc;
5861 5860 com_svc_t csp;
5862 5861 ls_code_t resp;
5863 5862
5864 5863 cmd = pkt->pkt_ulp_private;
5865 5864 port = cmd->cmd_port;
5866 5865
5867 5866 mutex_enter(&port->fp_mutex);
5868 5867 port->fp_out_fpcmds--;
5869 5868 mutex_exit(&port->fp_mutex);
5870 5869
5871 5870 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5872 5871 port, pkt, pkt->pkt_state);
5873 5872
5874 5873 if (FP_IS_PKT_ERROR(pkt)) {
5875 5874 (void) fp_common_intr(pkt, 1);
5876 5875 return;
5877 5876 }
5878 5877
5879 5878 /*
5880 5879 * Currently, we don't need to swap bytes here because qlc is faking the
5881 5880 * response for us and so endianness is getting taken care of. But we
5882 5881 * have to fix this and generalize this at some point
5883 5882 */
5884 5883 acc = (la_els_logi_t *)pkt->pkt_resp;
5885 5884
5886 5885 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5887 5886 sizeof (resp), DDI_DEV_AUTOINCR);
5888 5887
5889 5888 ASSERT(resp.ls_code == LA_ELS_ACC);
5890 5889 if (resp.ls_code != LA_ELS_ACC) {
5891 5890 (void) fp_common_intr(pkt, 1);
5892 5891 return;
5893 5892 }
5894 5893
5895 5894 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
5896 5895 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5897 5896
5898 5897 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5899 5898
5900 5899 ASSERT(!MUTEX_HELD(&port->fp_mutex));
5901 5900
5902 5901 mutex_enter(&port->fp_mutex);
5903 5902 state = FC_PORT_STATE_MASK(port->fp_state);
5904 5903 mutex_exit(&port->fp_mutex);
5905 5904
5906 5905 if (f_port == 0) {
5907 5906 if (state != FC_STATE_LOOP) {
5908 5907 swwn = &port->fp_service_params.nport_ww_name;
5909 5908
5910 5909 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5911 5910 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5912 5911 DDI_DEV_AUTOINCR);
5913 5912
5914 5913 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5915 5914 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5916 5915 DDI_DEV_AUTOINCR);
5917 5916
5918 5917 mutex_enter(&port->fp_mutex);
5919 5918
5920 5919 port->fp_topology = FC_TOP_PT_PT;
5921 5920 port->fp_total_devices = 1;
5922 5921 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5923 5922 port->fp_ptpt_master = 1;
5924 5923 /*
5925 5924 * Let us choose 'X' as S_ID and 'Y'
5926 5925 * as D_ID and that'll work; hopefully
5927 5926 * If not, it will get changed.
5928 5927 */
5929 5928 s_id = port->fp_instance + FP_DEFAULT_SID;
5930 5929 d_id = port->fp_instance + FP_DEFAULT_DID;
5931 5930 port->fp_port_id.port_id = s_id;
5932 5931 mutex_exit(&port->fp_mutex);
5933 5932
5934 5933 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
5935 5934 "pd %x", port->fp_port_id.port_id, d_id);
5936 5935 pd = fctl_create_remote_port(port,
5937 5936 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5938 5937 KM_NOSLEEP);
5939 5938 if (pd == NULL) {
5940 5939 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5941 5940 0, NULL, "couldn't create device"
5942 5941 " d_id=%X", d_id);
5943 5942 fp_iodone(cmd);
5944 5943 return;
5945 5944 }
5946 5945
5947 5946 cmd->cmd_pkt.pkt_tran_flags =
5948 5947 pkt->pkt_tran_flags;
5949 5948 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5950 5949 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5951 5950 cmd->cmd_retry_count = fp_retry_count;
5952 5951
5953 5952 fp_xlogi_init(port, cmd, s_id, d_id,
5954 5953 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5955 5954
5956 5955 (&cmd->cmd_pkt)->pkt_pd = pd;
5957 5956
5958 5957 /*
5959 5958 * We've just created this fc_remote_port_t, and
5960 5959 * we're about to use it to send a PLOGI, so
5961 5960 * bump the reference count right now. When
5962 5961 * the packet is freed, the reference count will
5963 5962 * be decremented. The ULP may also start using
5964 5963 * it, so mark it as given away as well.
5965 5964 */
5966 5965 pd->pd_ref_count++;
5967 5966 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5968 5967
5969 5968 if (fp_sendcmd(port, cmd,
5970 5969 port->fp_fca_handle) == FC_SUCCESS) {
5971 5970 return;
5972 5971 }
5973 5972 } else {
5974 5973 /*
5975 5974 * The device handles will be created when the
5976 5975 * unsolicited PLOGI is completed successfully
5977 5976 */
5978 5977 port->fp_ptpt_master = 0;
5979 5978 mutex_exit(&port->fp_mutex);
5980 5979 }
5981 5980 }
5982 5981 pkt->pkt_state = FC_PKT_FAILURE;
5983 5982 } else {
5984 5983 if (f_port) {
5985 5984 mutex_enter(&port->fp_mutex);
5986 5985 if (state == FC_STATE_LOOP) {
5987 5986 port->fp_topology = FC_TOP_PUBLIC_LOOP;
5988 5987 } else {
5989 5988 port->fp_topology = FC_TOP_FABRIC;
5990 5989
5991 5990 FC_GET_RSP(port, pkt->pkt_resp_acc,
5992 5991 (uint8_t *)&port->fp_fabric_name,
5993 5992 (uint8_t *)&acc->node_ww_name,
5994 5993 sizeof (la_wwn_t),
5995 5994 DDI_DEV_AUTOINCR);
5996 5995 }
5997 5996 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5998 5997 mutex_exit(&port->fp_mutex);
5999 5998 } else {
6000 5999 pkt->pkt_state = FC_PKT_FAILURE;
6001 6000 }
6002 6001 }
6003 6002 fp_iodone(cmd);
6004 6003 }
6005 6004
6006 6005
6007 6006 /*
6008 6007 * Handle solicited PLOGI response
6009 6008 */
6010 6009 static void
6011 6010 fp_plogi_intr(fc_packet_t *pkt)
6012 6011 {
6013 6012 int nl_port;
6014 6013 int bailout;
6015 6014 uint32_t d_id;
6016 6015 fp_cmd_t *cmd;
6017 6016 la_els_logi_t *acc;
6018 6017 fc_local_port_t *port;
6019 6018 fc_remote_port_t *pd;
6020 6019 la_wwn_t nwwn;
6021 6020 la_wwn_t pwwn;
6022 6021 ls_code_t resp;
6023 6022
6024 6023 nl_port = 0;
6025 6024 cmd = pkt->pkt_ulp_private;
6026 6025 port = cmd->cmd_port;
6027 6026 d_id = pkt->pkt_cmd_fhdr.d_id;
6028 6027
6029 6028 #ifndef __lock_lint
6030 6029 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6031 6030 #endif
6032 6031
6033 6032 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
6034 6033 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
6035 6034 cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
6036 6035
6037 6036 /*
6038 6037 * Bail out early on ULP initiated requests if the
6039 6038 * state change has occurred
6040 6039 */
6041 6040 mutex_enter(&port->fp_mutex);
6042 6041 port->fp_out_fpcmds--;
6043 6042 bailout = ((port->fp_statec_busy ||
6044 6043 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6045 6044 cmd->cmd_ulp_pkt) ? 1 : 0;
6046 6045 mutex_exit(&port->fp_mutex);
6047 6046
6048 6047 if (FP_IS_PKT_ERROR(pkt) || bailout) {
6049 6048 int skip_msg = 0;
6050 6049 int giveup = 0;
6051 6050
6052 6051 if (cmd->cmd_ulp_pkt) {
6053 6052 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6054 6053 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
6055 6054 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6056 6055 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6057 6056 }
6058 6057
6059 6058 /*
6060 6059 * If an unsolicited cross login already created
6061 6060 * a device speed up the discovery by not retrying
6062 6061 * the command mindlessly.
6063 6062 */
6064 6063 if (pkt->pkt_pd == NULL &&
6065 6064 fctl_get_remote_port_by_did(port, d_id) != NULL) {
6066 6065 fp_iodone(cmd);
6067 6066 return;
6068 6067 }
6069 6068
6070 6069 if (pkt->pkt_pd != NULL) {
6071 6070 giveup = (pkt->pkt_pd->pd_recepient ==
6072 6071 PD_PLOGI_RECEPIENT) ? 1 : 0;
6073 6072 if (giveup) {
6074 6073 /*
6075 6074 * This pd is marked as plogi
6076 6075 * recipient, stop retrying
6077 6076 */
6078 6077 FP_TRACE(FP_NHEAD1(3, 0),
6079 6078 "fp_plogi_intr: stop retry as"
6080 6079 " a cross login was accepted"
6081 6080 " from d_id=%x, port=%p.",
6082 6081 d_id, port);
6083 6082 fp_iodone(cmd);
6084 6083 return;
6085 6084 }
6086 6085 }
6087 6086
6088 6087 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6089 6088 return;
6090 6089 }
6091 6090
6092 6091 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
6093 6092 mutex_enter(&pd->pd_mutex);
6094 6093 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
6095 6094 skip_msg++;
6096 6095 }
6097 6096 mutex_exit(&pd->pd_mutex);
6098 6097 }
6099 6098
6100 6099 mutex_enter(&port->fp_mutex);
6101 6100 if (!bailout && !(skip_msg && port->fp_statec_busy) &&
6102 6101 port->fp_statec_busy <= 1 &&
6103 6102 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
6104 6103 mutex_exit(&port->fp_mutex);
6105 6104 /*
6106 6105 * In case of Login Collisions, JNI HBAs returns the
6107 6106 * FC pkt back to the Initiator with the state set to
6108 6107 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
6109 6108 * QLC HBAs handles such cases in the FW and doesnot
6110 6109 * return the LS_RJT with Logical error when
6111 6110 * login collision happens.
6112 6111 */
6113 6112 if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6114 6113 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6115 6114 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6116 6115 "PLOGI to %x failed", d_id);
6117 6116 }
6118 6117 FP_TRACE(FP_NHEAD2(9, 0),
6119 6118 "PLOGI to %x failed. state=%x reason=%x.",
6120 6119 d_id, pkt->pkt_state, pkt->pkt_reason);
6121 6120 } else {
6122 6121 mutex_exit(&port->fp_mutex);
6123 6122 }
6124 6123
6125 6124 fp_iodone(cmd);
6126 6125 return;
6127 6126 }
6128 6127
6129 6128 acc = (la_els_logi_t *)pkt->pkt_resp;
6130 6129
6131 6130 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6132 6131 sizeof (resp), DDI_DEV_AUTOINCR);
6133 6132
6134 6133 ASSERT(resp.ls_code == LA_ELS_ACC);
6135 6134 if (resp.ls_code != LA_ELS_ACC) {
6136 6135 (void) fp_common_intr(pkt, 1);
6137 6136 return;
6138 6137 }
6139 6138
6140 6139 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6141 6140 mutex_enter(&port->fp_mutex);
6142 6141 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6143 6142 mutex_exit(&port->fp_mutex);
6144 6143 fp_iodone(cmd);
6145 6144 return;
6146 6145 }
6147 6146
6148 6147 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6149 6148
6150 6149 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6151 6150 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6152 6151 DDI_DEV_AUTOINCR);
6153 6152
6154 6153 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6155 6154 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6156 6155 DDI_DEV_AUTOINCR);
6157 6156
6158 6157 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6159 6158 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6160 6159
6161 6160 if ((pd = pkt->pkt_pd) == NULL) {
6162 6161 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6163 6162 if (pd == NULL) {
6164 6163 FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x",
6165 6164 port->fp_port_id.port_id, d_id);
6166 6165 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6167 6166 PD_PLOGI_INITIATOR, KM_NOSLEEP);
6168 6167 if (pd == NULL) {
6169 6168 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6170 6169 "couldn't create port device handles"
6171 6170 " d_id=%x", d_id);
6172 6171 fp_iodone(cmd);
6173 6172 return;
6174 6173 }
6175 6174 } else {
6176 6175 fc_remote_port_t *tmp_pd;
6177 6176
6178 6177 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6179 6178 if (tmp_pd != NULL) {
6180 6179 fp_iodone(cmd);
6181 6180 return;
6182 6181 }
6183 6182
6184 6183 mutex_enter(&port->fp_mutex);
6185 6184 mutex_enter(&pd->pd_mutex);
6186 6185 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6187 6186 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6188 6187 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6189 6188 }
6190 6189
6191 6190 if (pd->pd_type == PORT_DEVICE_OLD) {
6192 6191 if (pd->pd_port_id.port_id != d_id) {
6193 6192 fctl_delist_did_table(port, pd);
6194 6193 pd->pd_type = PORT_DEVICE_CHANGED;
6195 6194 pd->pd_port_id.port_id = d_id;
6196 6195 } else {
6197 6196 pd->pd_type = PORT_DEVICE_NOCHANGE;
6198 6197 }
6199 6198 }
6200 6199
6201 6200 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6202 6201 char ww_name[17];
6203 6202
6204 6203 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6205 6204
6206 6205 mutex_exit(&pd->pd_mutex);
6207 6206 mutex_exit(&port->fp_mutex);
6208 6207 FP_TRACE(FP_NHEAD2(9, 0),
6209 6208 "Possible Duplicate name or address"
6210 6209 " identifiers in the PLOGI response"
6211 6210 " D_ID=%x, PWWN=%s: Please check the"
6212 6211 " configuration", d_id, ww_name);
6213 6212 fp_iodone(cmd);
6214 6213 return;
6215 6214 }
6216 6215 fctl_enlist_did_table(port, pd);
6217 6216 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6218 6217 mutex_exit(&pd->pd_mutex);
6219 6218 mutex_exit(&port->fp_mutex);
6220 6219 }
6221 6220 } else {
6222 6221 fc_remote_port_t *tmp_pd, *new_wwn_pd;
6223 6222
6224 6223 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6225 6224 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6226 6225
6227 6226 mutex_enter(&port->fp_mutex);
6228 6227 mutex_enter(&pd->pd_mutex);
6229 6228 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6230 6229 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6231 6230 " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6232 6231 pd->pd_type);
6233 6232 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6234 6233 pd->pd_type == PORT_DEVICE_OLD) ||
6235 6234 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6236 6235 pd->pd_type = PORT_DEVICE_NOCHANGE;
6237 6236 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6238 6237 pd->pd_type = PORT_DEVICE_NEW;
6239 6238 }
6240 6239 } else {
6241 6240 char old_name[17];
6242 6241 char new_name[17];
6243 6242
6244 6243 fc_wwn_to_str(&pd->pd_port_name, old_name);
6245 6244 fc_wwn_to_str(&pwwn, new_name);
6246 6245
6247 6246 FP_TRACE(FP_NHEAD1(9, 0),
6248 6247 "fp_plogi_intr: PWWN of a device with D_ID=%x "
6249 6248 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6250 6249 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6251 6250 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6252 6251 cmd->cmd_ulp_pkt, bailout);
6253 6252
6254 6253 FP_TRACE(FP_NHEAD2(9, 0),
6255 6254 "PWWN of a device with D_ID=%x changed."
6256 6255 " New PWWN = %s, OLD PWWN = %s", d_id,
6257 6256 new_name, old_name);
6258 6257
6259 6258 if (cmd->cmd_ulp_pkt && !bailout) {
6260 6259 fc_remote_node_t *rnodep;
6261 6260 fc_portmap_t *changelist;
6262 6261 fc_portmap_t *listptr;
6263 6262 int len = 1;
6264 6263 /* # entries in changelist */
6265 6264
6266 6265 fctl_delist_pwwn_table(port, pd);
6267 6266
6268 6267 /*
6269 6268 * Lets now check if there already is a pd with
6270 6269 * this new WWN in the table. If so, we'll mark
6271 6270 * it as invalid
6272 6271 */
6273 6272
6274 6273 if (new_wwn_pd) {
6275 6274 /*
6276 6275 * There is another pd with in the pwwn
6277 6276 * table with the same WWN that we got
6278 6277 * in the PLOGI payload. We have to get
6279 6278 * it out of the pwwn table, update the
6280 6279 * pd's state (fp_fillout_old_map does
6281 6280 * this for us) and add it to the
6282 6281 * changelist that goes up to ULPs.
6283 6282 *
6284 6283 * len is length of changelist and so
6285 6284 * increment it.
6286 6285 */
6287 6286 len++;
6288 6287
6289 6288 if (tmp_pd != pd) {
6290 6289 /*
6291 6290 * Odd case where pwwn and did
6292 6291 * tables are out of sync but
6293 6292 * we will handle that too. See
6294 6293 * more comments below.
6295 6294 *
6296 6295 * One more device that ULPs
6297 6296 * should know about and so len
6298 6297 * gets incremented again.
6299 6298 */
6300 6299 len++;
6301 6300 }
6302 6301
6303 6302 listptr = changelist = kmem_zalloc(len *
6304 6303 sizeof (*changelist), KM_SLEEP);
6305 6304
6306 6305 mutex_enter(&new_wwn_pd->pd_mutex);
6307 6306 rnodep = new_wwn_pd->pd_remote_nodep;
6308 6307 mutex_exit(&new_wwn_pd->pd_mutex);
6309 6308
6310 6309 /*
6311 6310 * Hold the fd_mutex since
6312 6311 * fctl_copy_portmap_held expects it.
6313 6312 * Preserve lock hierarchy by grabbing
6314 6313 * fd_mutex before pd_mutex
6315 6314 */
6316 6315 if (rnodep) {
6317 6316 mutex_enter(&rnodep->fd_mutex);
6318 6317 }
6319 6318 mutex_enter(&new_wwn_pd->pd_mutex);
6320 6319 fp_fillout_old_map_held(listptr++,
6321 6320 new_wwn_pd, 0);
6322 6321 mutex_exit(&new_wwn_pd->pd_mutex);
6323 6322 if (rnodep) {
6324 6323 mutex_exit(&rnodep->fd_mutex);
6325 6324 }
6326 6325
6327 6326 /*
6328 6327 * Safety check :
6329 6328 * Lets ensure that the pwwn and did
6330 6329 * tables are in sync. Ideally, we
6331 6330 * should not find that these two pd's
6332 6331 * are different.
6333 6332 */
6334 6333 if (tmp_pd != pd) {
6335 6334 mutex_enter(&tmp_pd->pd_mutex);
6336 6335 rnodep =
6337 6336 tmp_pd->pd_remote_nodep;
6338 6337 mutex_exit(&tmp_pd->pd_mutex);
6339 6338
6340 6339 /* As above grab fd_mutex */
6341 6340 if (rnodep) {
6342 6341 mutex_enter(&rnodep->
6343 6342 fd_mutex);
6344 6343 }
6345 6344 mutex_enter(&tmp_pd->pd_mutex);
6346 6345
6347 6346 fp_fillout_old_map_held(
6348 6347 listptr++, tmp_pd, 0);
6349 6348
6350 6349 mutex_exit(&tmp_pd->pd_mutex);
6351 6350 if (rnodep) {
6352 6351 mutex_exit(&rnodep->
6353 6352 fd_mutex);
6354 6353 }
6355 6354
6356 6355 /*
6357 6356 * Now add "pd" (not tmp_pd)
6358 6357 * to fp_did_table to sync it up
6359 6358 * with fp_pwwn_table
6360 6359 *
6361 6360 * pd->pd_mutex is already held
6362 6361 * at this point
6363 6362 */
6364 6363 fctl_enlist_did_table(port, pd);
6365 6364 }
6366 6365 } else {
6367 6366 listptr = changelist = kmem_zalloc(
6368 6367 sizeof (*changelist), KM_SLEEP);
6369 6368 }
6370 6369
6371 6370 ASSERT(changelist != NULL);
6372 6371
6373 6372 fp_fillout_changed_map(listptr, pd, &d_id,
6374 6373 &pwwn);
6375 6374 fctl_enlist_pwwn_table(port, pd);
6376 6375
6377 6376 mutex_exit(&pd->pd_mutex);
6378 6377 mutex_exit(&port->fp_mutex);
6379 6378
6380 6379 fp_iodone(cmd);
6381 6380
6382 6381 (void) fp_ulp_devc_cb(port, changelist, len,
6383 6382 len, KM_NOSLEEP, 0);
6384 6383
6385 6384 return;
6386 6385 }
6387 6386 }
6388 6387
6389 6388 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6390 6389 nl_port = 1;
6391 6390 }
6392 6391 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6393 6392 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6394 6393 }
6395 6394
6396 6395 mutex_exit(&pd->pd_mutex);
6397 6396 mutex_exit(&port->fp_mutex);
6398 6397
6399 6398 if (tmp_pd == NULL) {
6400 6399 mutex_enter(&port->fp_mutex);
6401 6400 mutex_enter(&pd->pd_mutex);
6402 6401 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6403 6402 char ww_name[17];
6404 6403
6405 6404 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6406 6405 mutex_exit(&pd->pd_mutex);
6407 6406 mutex_exit(&port->fp_mutex);
6408 6407 FP_TRACE(FP_NHEAD2(9, 0),
6409 6408 "Possible Duplicate name or address"
6410 6409 " identifiers in the PLOGI response"
6411 6410 " D_ID=%x, PWWN=%s: Please check the"
6412 6411 " configuration", d_id, ww_name);
6413 6412 fp_iodone(cmd);
6414 6413 return;
6415 6414 }
6416 6415 fctl_enlist_did_table(port, pd);
6417 6416 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6418 6417 mutex_exit(&pd->pd_mutex);
6419 6418 mutex_exit(&port->fp_mutex);
6420 6419 }
6421 6420 }
6422 6421 fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6423 6422 FC_TRAN_CLASS(pkt->pkt_tran_flags));
6424 6423
6425 6424 if (cmd->cmd_ulp_pkt) {
6426 6425 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6427 6426 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6428 6427 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6429 6428 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6430 6429 if (pd != NULL) {
6431 6430 FP_TRACE(FP_NHEAD1(9, 0),
6432 6431 "fp_plogi_intr;"
6433 6432 "ulp_pkt's pd is NULL, get a pd %p",
6434 6433 pd);
6435 6434 mutex_enter(&pd->pd_mutex);
6436 6435 pd->pd_ref_count++;
6437 6436 mutex_exit(&pd->pd_mutex);
6438 6437 }
6439 6438 cmd->cmd_ulp_pkt->pkt_pd = pd;
6440 6439 }
6441 6440 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6442 6441 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6443 6442 sizeof (fc_frame_hdr_t));
6444 6443 bcopy((caddr_t)pkt->pkt_resp,
6445 6444 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6446 6445 sizeof (la_els_logi_t));
6447 6446 }
6448 6447
6449 6448 mutex_enter(&port->fp_mutex);
6450 6449 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6451 6450 mutex_enter(&pd->pd_mutex);
6452 6451
6453 6452 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6454 6453 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6455 6454 cmd->cmd_retry_count = fp_retry_count;
6456 6455
6457 6456 /*
6458 6457 * If the fc_remote_port_t pointer is not set in the given
6459 6458 * fc_packet_t, then this fc_remote_port_t must have just
6460 6459 * been created. Save the pointer and also increment the
6461 6460 * fc_remote_port_t reference count.
6462 6461 */
6463 6462 if (pkt->pkt_pd == NULL) {
6464 6463 pkt->pkt_pd = pd;
6465 6464 pd->pd_ref_count++; /* It's in use! */
6466 6465 }
6467 6466
6468 6467 fp_adisc_init(cmd, cmd->cmd_job);
6469 6468
6470 6469 pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6471 6470 pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6472 6471
6473 6472 mutex_exit(&pd->pd_mutex);
6474 6473 mutex_exit(&port->fp_mutex);
6475 6474
6476 6475 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6477 6476 return;
6478 6477 }
6479 6478 } else {
6480 6479 mutex_exit(&port->fp_mutex);
6481 6480 }
6482 6481
6483 6482 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6484 6483 mutex_enter(&port->fp_mutex);
6485 6484 mutex_enter(&pd->pd_mutex);
6486 6485
6487 6486 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6488 6487 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6489 6488 cmd->cmd_retry_count = fp_retry_count;
6490 6489
6491 6490 fp_logo_init(pd, cmd, cmd->cmd_job);
6492 6491
6493 6492 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6494 6493 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6495 6494
6496 6495 mutex_exit(&pd->pd_mutex);
6497 6496 mutex_exit(&port->fp_mutex);
6498 6497
6499 6498 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6500 6499 return;
6501 6500 }
6502 6501
6503 6502 }
6504 6503 fp_iodone(cmd);
6505 6504 }
6506 6505
6507 6506
6508 6507 /*
6509 6508 * Handle solicited ADISC response
6510 6509 */
6511 6510 static void
6512 6511 fp_adisc_intr(fc_packet_t *pkt)
6513 6512 {
6514 6513 int rval;
6515 6514 int bailout;
6516 6515 fp_cmd_t *cmd, *logi_cmd;
6517 6516 fc_local_port_t *port;
6518 6517 fc_remote_port_t *pd;
6519 6518 la_els_adisc_t *acc;
6520 6519 ls_code_t resp;
6521 6520 fc_hardaddr_t ha;
6522 6521 fc_portmap_t *changelist;
6523 6522 int initiator, adiscfail = 0;
6524 6523
6525 6524 pd = pkt->pkt_pd;
6526 6525 cmd = pkt->pkt_ulp_private;
6527 6526 port = cmd->cmd_port;
6528 6527
6529 6528 #ifndef __lock_lint
6530 6529 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6531 6530 #endif
6532 6531
6533 6532 ASSERT(pd != NULL && port != NULL && cmd != NULL);
6534 6533
6535 6534 mutex_enter(&port->fp_mutex);
6536 6535 port->fp_out_fpcmds--;
6537 6536 bailout = ((port->fp_statec_busy ||
6538 6537 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6539 6538 cmd->cmd_ulp_pkt) ? 1 : 0;
6540 6539 mutex_exit(&port->fp_mutex);
6541 6540
6542 6541 if (bailout) {
6543 6542 fp_iodone(cmd);
6544 6543 return;
6545 6544 }
6546 6545
6547 6546 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6548 6547 acc = (la_els_adisc_t *)pkt->pkt_resp;
6549 6548
6550 6549 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6551 6550 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6552 6551
6553 6552 if (resp.ls_code == LA_ELS_ACC) {
6554 6553 int is_private;
6555 6554
6556 6555 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
6557 6556 (uint8_t *)&acc->hard_addr, sizeof (ha),
6558 6557 DDI_DEV_AUTOINCR);
6559 6558
6560 6559 mutex_enter(&port->fp_mutex);
6561 6560
6562 6561 is_private =
6563 6562 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6564 6563
6565 6564 mutex_enter(&pd->pd_mutex);
6566 6565 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6567 6566 fctl_enlist_did_table(port, pd);
6568 6567 }
6569 6568 mutex_exit(&pd->pd_mutex);
6570 6569
6571 6570 mutex_exit(&port->fp_mutex);
6572 6571
6573 6572 mutex_enter(&pd->pd_mutex);
6574 6573 if (pd->pd_type != PORT_DEVICE_NEW) {
6575 6574 if (is_private && (pd->pd_hard_addr.hard_addr !=
6576 6575 ha.hard_addr)) {
6577 6576 pd->pd_type = PORT_DEVICE_CHANGED;
6578 6577 } else {
6579 6578 pd->pd_type = PORT_DEVICE_NOCHANGE;
6580 6579 }
6581 6580 }
6582 6581
6583 6582 if (is_private && (ha.hard_addr &&
6584 6583 pd->pd_port_id.port_id != ha.hard_addr)) {
6585 6584 char ww_name[17];
6586 6585
6587 6586 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6588 6587
6589 6588 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6590 6589 "NL_Port Identifier %x doesn't match"
6591 6590 " with Hard Address %x, Will use Port"
6592 6591 " WWN %s", pd->pd_port_id.port_id,
6593 6592 ha.hard_addr, ww_name);
6594 6593
6595 6594 pd->pd_hard_addr.hard_addr = 0;
6596 6595 } else {
6597 6596 pd->pd_hard_addr.hard_addr = ha.hard_addr;
6598 6597 }
6599 6598 mutex_exit(&pd->pd_mutex);
6600 6599 } else {
6601 6600 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6602 6601 return;
6603 6602 }
6604 6603 }
6605 6604 } else {
6606 6605 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6607 6606 return;
6608 6607 }
6609 6608
6610 6609 mutex_enter(&port->fp_mutex);
6611 6610 if (port->fp_statec_busy <= 1) {
6612 6611 mutex_exit(&port->fp_mutex);
6613 6612 if (pkt->pkt_state == FC_PKT_LS_RJT &&
6614 6613 pkt->pkt_reason == FC_REASON_CMD_UNABLE) {
6615 6614 uchar_t class;
6616 6615 int cmd_flag;
6617 6616 uint32_t src_id;
6618 6617
6619 6618 class = fp_get_nextclass(port,
6620 6619 FC_TRAN_CLASS_INVALID);
6621 6620 if (class == FC_TRAN_CLASS_INVALID) {
6622 6621 fp_iodone(cmd);
6623 6622 return;
6624 6623 }
6625 6624
6626 6625 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; "
6627 6626 "fp_state=0x%x, pkt_state=0x%x, "
6628 6627 "reason=0x%x, class=0x%x",
6629 6628 port->fp_state, pkt->pkt_state,
6630 6629 pkt->pkt_reason, class);
6631 6630 cmd_flag = FP_CMD_PLOGI_RETAIN;
6632 6631
6633 6632 logi_cmd = fp_alloc_pkt(port,
6634 6633 sizeof (la_els_logi_t),
6635 6634 sizeof (la_els_logi_t), KM_SLEEP, pd);
6636 6635 if (logi_cmd == NULL) {
6637 6636 fp_iodone(cmd);
6638 6637 return;
6639 6638 }
6640 6639
6641 6640 logi_cmd->cmd_pkt.pkt_tran_flags =
6642 6641 FC_TRAN_INTR | class;
6643 6642 logi_cmd->cmd_pkt.pkt_tran_type =
6644 6643 FC_PKT_EXCHANGE;
6645 6644 logi_cmd->cmd_flags = cmd_flag;
6646 6645 logi_cmd->cmd_retry_count = fp_retry_count;
6647 6646 logi_cmd->cmd_ulp_pkt = NULL;
6648 6647
6649 6648 mutex_enter(&port->fp_mutex);
6650 6649 src_id = port->fp_port_id.port_id;
6651 6650 mutex_exit(&port->fp_mutex);
6652 6651
6653 6652 fp_xlogi_init(port, logi_cmd, src_id,
6654 6653 pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr,
6655 6654 cmd->cmd_job, LA_ELS_PLOGI);
6656 6655 if (pd) {
6657 6656 mutex_enter(&pd->pd_mutex);
6658 6657 pd->pd_flags = PD_ELS_IN_PROGRESS;
6659 6658 mutex_exit(&pd->pd_mutex);
6660 6659 }
6661 6660
6662 6661 if (fp_sendcmd(port, logi_cmd,
6663 6662 port->fp_fca_handle) == FC_SUCCESS) {
6664 6663 fp_free_pkt(cmd);
6665 6664 return;
6666 6665 } else {
6667 6666 fp_free_pkt(logi_cmd);
6668 6667 }
6669 6668 } else {
6670 6669 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6671 6670 "ADISC to %x failed, cmd_flags=%x",
6672 6671 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6673 6672 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6674 6673 adiscfail = 1;
6675 6674 }
6676 6675 } else {
6677 6676 mutex_exit(&port->fp_mutex);
6678 6677 }
6679 6678 }
6680 6679
6681 6680 if (cmd->cmd_ulp_pkt) {
6682 6681 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6683 6682 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6684 6683 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6685 6684 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6686 6685 cmd->cmd_ulp_pkt->pkt_pd = pd;
6687 6686 FP_TRACE(FP_NHEAD1(9, 0),
6688 6687 "fp_adisc__intr;"
6689 6688 "ulp_pkt's pd is NULL, get a pd %p",
6690 6689 pd);
6691 6690
6692 6691 }
6693 6692 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6694 6693 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6695 6694 sizeof (fc_frame_hdr_t));
6696 6695 bcopy((caddr_t)pkt->pkt_resp,
6697 6696 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6698 6697 sizeof (la_els_adisc_t));
6699 6698 }
6700 6699
6701 6700 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6702 6701 FP_TRACE(FP_NHEAD1(9, 0),
6703 6702 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6704 6703 "fp_retry_count=%x, ulp_pkt=%p",
6705 6704 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6706 6705
6707 6706 mutex_enter(&port->fp_mutex);
6708 6707 mutex_enter(&pd->pd_mutex);
6709 6708
6710 6709 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6711 6710 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6712 6711 cmd->cmd_retry_count = fp_retry_count;
6713 6712
6714 6713 fp_logo_init(pd, cmd, cmd->cmd_job);
6715 6714
6716 6715 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6717 6716 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6718 6717
6719 6718 mutex_exit(&pd->pd_mutex);
6720 6719 mutex_exit(&port->fp_mutex);
6721 6720
6722 6721 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6723 6722 if (adiscfail) {
6724 6723 mutex_enter(&pd->pd_mutex);
6725 6724 initiator =
6726 6725 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
6727 6726 pd->pd_state = PORT_DEVICE_VALID;
6728 6727 pd->pd_aux_flags |= PD_LOGGED_OUT;
6729 6728 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6730 6729 pd->pd_type = PORT_DEVICE_NEW;
6731 6730 } else {
6732 6731 pd->pd_type = PORT_DEVICE_NOCHANGE;
6733 6732 }
6734 6733 mutex_exit(&pd->pd_mutex);
6735 6734
6736 6735 changelist =
6737 6736 kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6738 6737
6739 6738 if (initiator) {
6740 6739 fp_unregister_login(pd);
6741 6740 fctl_copy_portmap(changelist, pd);
6742 6741 } else {
6743 6742 fp_fillout_old_map(changelist, pd, 0);
6744 6743 }
6745 6744
6746 6745 FP_TRACE(FP_NHEAD1(9, 0),
6747 6746 "fp_adisc_intr: Dev change notification "
6748 6747 "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6749 6748 "map_flags=%x initiator=%d", port, pd,
6750 6749 changelist->map_type, changelist->map_state,
6751 6750 changelist->map_flags, initiator);
6752 6751
6753 6752 (void) fp_ulp_devc_cb(port, changelist,
6754 6753 1, 1, KM_SLEEP, 0);
6755 6754 }
6756 6755 if (rval == FC_SUCCESS) {
6757 6756 return;
6758 6757 }
6759 6758 }
6760 6759 fp_iodone(cmd);
6761 6760 }
6762 6761
6763 6762
6764 6763 /*
6765 6764 * Handle solicited LOGO response
6766 6765 */
6767 6766 static void
6768 6767 fp_logo_intr(fc_packet_t *pkt)
6769 6768 {
6770 6769 ls_code_t resp;
6771 6770 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6772 6771
6773 6772 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6774 6773 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6775 6774 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6776 6775
6777 6776 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6778 6777 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6779 6778
6780 6779 if (FP_IS_PKT_ERROR(pkt)) {
6781 6780 (void) fp_common_intr(pkt, 1);
6782 6781 return;
6783 6782 }
6784 6783
6785 6784 ASSERT(resp.ls_code == LA_ELS_ACC);
6786 6785 if (resp.ls_code != LA_ELS_ACC) {
6787 6786 (void) fp_common_intr(pkt, 1);
6788 6787 return;
6789 6788 }
6790 6789
6791 6790 if (pkt->pkt_pd != NULL) {
6792 6791 fp_unregister_login(pkt->pkt_pd);
6793 6792 }
6794 6793
6795 6794 fp_iodone(pkt->pkt_ulp_private);
6796 6795 }
6797 6796
6798 6797
6799 6798 /*
6800 6799 * Handle solicited RNID response
6801 6800 */
6802 6801 static void
6803 6802 fp_rnid_intr(fc_packet_t *pkt)
6804 6803 {
6805 6804 ls_code_t resp;
6806 6805 job_request_t *job;
6807 6806 fp_cmd_t *cmd;
6808 6807 la_els_rnid_acc_t *acc;
6809 6808 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6810 6809
6811 6810 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6812 6811 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6813 6812 cmd = pkt->pkt_ulp_private;
6814 6813
6815 6814 mutex_enter(&cmd->cmd_port->fp_mutex);
6816 6815 cmd->cmd_port->fp_out_fpcmds--;
6817 6816 mutex_exit(&cmd->cmd_port->fp_mutex);
6818 6817
6819 6818 job = cmd->cmd_job;
6820 6819 ASSERT(job->job_private != NULL);
6821 6820
6822 6821 /* If failure or LS_RJT then retry the packet, if needed */
6823 6822 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6824 6823 (void) fp_common_intr(pkt, 1);
6825 6824 return;
6826 6825 }
6827 6826
6828 6827 /* Save node_id memory allocated in ioctl code */
6829 6828 acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6830 6829
6831 6830 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6832 6831 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6833 6832
6834 6833 /* wakeup the ioctl thread and free the pkt */
6835 6834 fp_iodone(cmd);
6836 6835 }
6837 6836
6838 6837
6839 6838 /*
6840 6839 * Handle solicited RLS response
6841 6840 */
6842 6841 static void
6843 6842 fp_rls_intr(fc_packet_t *pkt)
6844 6843 {
6845 6844 ls_code_t resp;
6846 6845 job_request_t *job;
6847 6846 fp_cmd_t *cmd;
6848 6847 la_els_rls_acc_t *acc;
6849 6848 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6850 6849
6851 6850 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6852 6851 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6853 6852 cmd = pkt->pkt_ulp_private;
6854 6853
6855 6854 mutex_enter(&cmd->cmd_port->fp_mutex);
6856 6855 cmd->cmd_port->fp_out_fpcmds--;
6857 6856 mutex_exit(&cmd->cmd_port->fp_mutex);
6858 6857
6859 6858 job = cmd->cmd_job;
6860 6859 ASSERT(job->job_private != NULL);
6861 6860
6862 6861 /* If failure or LS_RJT then retry the packet, if needed */
6863 6862 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6864 6863 (void) fp_common_intr(pkt, 1);
6865 6864 return;
6866 6865 }
6867 6866
6868 6867 /* Save link error status block in memory allocated in ioctl code */
6869 6868 acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6870 6869
6871 6870 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6872 6871 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6873 6872 DDI_DEV_AUTOINCR);
6874 6873
6875 6874 /* wakeup the ioctl thread and free the pkt */
6876 6875 fp_iodone(cmd);
6877 6876 }
6878 6877
6879 6878
6880 6879 /*
6881 6880 * A solicited command completion interrupt (mostly for commands
6882 6881 * that require almost no post processing such as SCR ELS)
6883 6882 */
6884 6883 static void
6885 6884 fp_intr(fc_packet_t *pkt)
6886 6885 {
6887 6886 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6888 6887 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6889 6888 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6890 6889
6891 6890 if (FP_IS_PKT_ERROR(pkt)) {
6892 6891 (void) fp_common_intr(pkt, 1);
6893 6892 return;
6894 6893 }
6895 6894 fp_iodone(pkt->pkt_ulp_private);
6896 6895 }
6897 6896
6898 6897
6899 6898 /*
6900 6899 * Handle the underlying port's state change
6901 6900 */
6902 6901 static void
6903 6902 fp_statec_cb(opaque_t port_handle, uint32_t state)
6904 6903 {
6905 6904 fc_local_port_t *port = port_handle;
6906 6905 job_request_t *job;
6907 6906
6908 6907 /*
6909 6908 * If it is not possible to process the callbacks
6910 6909 * just drop the callback on the floor; Don't bother
6911 6910 * to do something that isn't safe at this time
6912 6911 */
6913 6912 mutex_enter(&port->fp_mutex);
6914 6913 if ((port->fp_soft_state &
6915 6914 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6916 6915 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6917 6916 mutex_exit(&port->fp_mutex);
6918 6917 return;
6919 6918 }
6920 6919
6921 6920 if (port->fp_statec_busy == 0) {
6922 6921 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6923 6922 #ifdef DEBUG
6924 6923 } else {
6925 6924 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6926 6925 #endif
6927 6926 }
6928 6927
6929 6928 port->fp_statec_busy++;
6930 6929
6931 6930 /*
6932 6931 * For now, force the trusted method of device authentication (by
6933 6932 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6934 6933 */
6935 6934 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6936 6935 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6937 6936 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6938 6937 fp_port_offline(port, 0);
6939 6938 }
6940 6939 mutex_exit(&port->fp_mutex);
6941 6940
6942 6941 switch (FC_PORT_STATE_MASK(state)) {
6943 6942 case FC_STATE_OFFLINE:
6944 6943 job = fctl_alloc_job(JOB_PORT_OFFLINE,
6945 6944 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6946 6945 if (job == NULL) {
6947 6946 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6948 6947 " fp_statec_cb() couldn't submit a job "
6949 6948 " to the thread: failing..");
6950 6949 mutex_enter(&port->fp_mutex);
6951 6950 if (--port->fp_statec_busy == 0) {
6952 6951 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6953 6952 }
6954 6953 mutex_exit(&port->fp_mutex);
6955 6954 return;
6956 6955 }
6957 6956 mutex_enter(&port->fp_mutex);
6958 6957 /*
6959 6958 * Zero out this field so that we do not retain
6960 6959 * the fabric name as its no longer valid
6961 6960 */
6962 6961 bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6963 6962 port->fp_state = state;
6964 6963 mutex_exit(&port->fp_mutex);
6965 6964
6966 6965 fctl_enque_job(port, job);
6967 6966 break;
6968 6967
6969 6968 case FC_STATE_ONLINE:
6970 6969 case FC_STATE_LOOP:
6971 6970 mutex_enter(&port->fp_mutex);
6972 6971 port->fp_state = state;
6973 6972
6974 6973 if (port->fp_offline_tid) {
6975 6974 timeout_id_t tid;
6976 6975
6977 6976 tid = port->fp_offline_tid;
6978 6977 port->fp_offline_tid = NULL;
6979 6978 mutex_exit(&port->fp_mutex);
6980 6979 (void) untimeout(tid);
6981 6980 } else {
6982 6981 mutex_exit(&port->fp_mutex);
6983 6982 }
6984 6983
6985 6984 job = fctl_alloc_job(JOB_PORT_ONLINE,
6986 6985 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6987 6986 if (job == NULL) {
6988 6987 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6989 6988 "fp_statec_cb() couldn't submit a job "
6990 6989 "to the thread: failing..");
6991 6990
6992 6991 mutex_enter(&port->fp_mutex);
6993 6992 if (--port->fp_statec_busy == 0) {
6994 6993 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6995 6994 }
6996 6995 mutex_exit(&port->fp_mutex);
6997 6996 return;
6998 6997 }
6999 6998 fctl_enque_job(port, job);
7000 6999 break;
7001 7000
7002 7001 case FC_STATE_RESET_REQUESTED:
7003 7002 mutex_enter(&port->fp_mutex);
7004 7003 port->fp_state = FC_STATE_OFFLINE;
7005 7004 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
7006 7005 mutex_exit(&port->fp_mutex);
7007 7006 /* FALLTHROUGH */
7008 7007
7009 7008 case FC_STATE_RESET:
7010 7009 job = fctl_alloc_job(JOB_ULP_NOTIFY,
7011 7010 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
7012 7011 if (job == NULL) {
7013 7012 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
7014 7013 "fp_statec_cb() couldn't submit a job"
7015 7014 " to the thread: failing..");
7016 7015
7017 7016 mutex_enter(&port->fp_mutex);
7018 7017 if (--port->fp_statec_busy == 0) {
7019 7018 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7020 7019 }
7021 7020 mutex_exit(&port->fp_mutex);
7022 7021 return;
7023 7022 }
7024 7023
7025 7024 /* squeeze into some field in the job structure */
7026 7025 job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
7027 7026 fctl_enque_job(port, job);
7028 7027 break;
7029 7028
7030 7029 case FC_STATE_TARGET_PORT_RESET:
7031 7030 (void) fp_ulp_notify(port, state, KM_NOSLEEP);
7032 7031 /* FALLTHROUGH */
7033 7032
7034 7033 case FC_STATE_NAMESERVICE:
7035 7034 /* FALLTHROUGH */
7036 7035
7037 7036 default:
7038 7037 mutex_enter(&port->fp_mutex);
7039 7038 if (--port->fp_statec_busy == 0) {
7040 7039 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7041 7040 }
7042 7041 mutex_exit(&port->fp_mutex);
7043 7042 break;
7044 7043 }
7045 7044 }
7046 7045
7047 7046
7048 7047 /*
7049 7048 * Register with the Name Server for RSCNs
7050 7049 */
7051 7050 static int
7052 7051 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
7053 7052 int sleep)
7054 7053 {
7055 7054 uint32_t s_id;
7056 7055 uchar_t class;
7057 7056 fc_scr_req_t payload;
7058 7057 fp_cmd_t *cmd;
7059 7058 fc_packet_t *pkt;
7060 7059
7061 7060 mutex_enter(&port->fp_mutex);
7062 7061 s_id = port->fp_port_id.port_id;
7063 7062 class = port->fp_ns_login_class;
7064 7063 mutex_exit(&port->fp_mutex);
7065 7064
7066 7065 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
7067 7066 sizeof (fc_scr_resp_t), sleep, NULL);
7068 7067 if (cmd == NULL) {
7069 7068 return (FC_NOMEM);
7070 7069 }
7071 7070
7072 7071 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
7073 7072 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
7074 7073 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
7075 7074 cmd->cmd_retry_count = fp_retry_count;
7076 7075 cmd->cmd_ulp_pkt = NULL;
7077 7076
7078 7077 pkt = &cmd->cmd_pkt;
7079 7078 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
7080 7079
7081 7080 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
7082 7081
7083 7082 payload.ls_code.ls_code = LA_ELS_SCR;
7084 7083 payload.ls_code.mbz = 0;
7085 7084 payload.scr_rsvd = 0;
7086 7085 payload.scr_func = scr_func;
7087 7086
7088 7087 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
7089 7088 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
7090 7089
7091 7090 job->job_counter = 1;
7092 7091
7093 7092 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
7094 7093 fp_iodone(cmd);
7095 7094 }
7096 7095
7097 7096 return (FC_SUCCESS);
7098 7097 }
7099 7098
7100 7099
7101 7100 /*
7102 7101 * There are basically two methods to determine the total number of
7103 7102 * devices out in the NS database; Reading the details of the two
7104 7103 * methods described below, it shouldn't be hard to identify which
7105 7104 * of the two methods is better.
7106 7105 *
7107 7106 * Method 1.
7108 7107 * Iteratively issue GANs until all ports identifiers are walked
7109 7108 *
7110 7109 * Method 2.
7111 7110 * Issue GID_PT (get port Identifiers) with Maximum residual
7112 7111 * field in the request CT HEADER set to accommodate only the
7113 7112 * CT HEADER in the response frame. And if FC-GS2 has been
7114 7113 * carefully read, the NS here has a chance to FS_ACC the
7115 7114 * request and indicate the residual size in the FS_ACC.
7116 7115 *
7117 7116 * Method 2 is wonderful, although it's not mandatory for the NS
7118 7117 * to update the Maximum/Residual Field as can be seen in 4.3.1.6
7119 7118 * (note with particular care the use of the auxiliary verb 'may')
7120 7119 *
7121 7120 */
7122 7121 static int
7123 7122 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
7124 7123 int sleep)
7125 7124 {
7126 7125 int flags;
7127 7126 int rval;
7128 7127 uint32_t src_id;
7129 7128 fctl_ns_req_t *ns_cmd;
7130 7129
7131 7130 ASSERT(!MUTEX_HELD(&port->fp_mutex));
7132 7131
7133 7132 mutex_enter(&port->fp_mutex);
7134 7133 src_id = port->fp_port_id.port_id;
7135 7134 mutex_exit(&port->fp_mutex);
7136 7135
7137 7136 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7138 7137 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
7139 7138 sizeof (ns_resp_gid_pt_t), 0,
7140 7139 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
7141 7140
7142 7141 if (ns_cmd == NULL) {
7143 7142 return (FC_NOMEM);
7144 7143 }
7145 7144
7146 7145 ns_cmd->ns_cmd_code = NS_GID_PT;
7147 7146 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
7148 7147 = FC_NS_PORT_NX; /* All port types */
7149 7148 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
7150 7149
7151 7150 } else {
7152 7151 uint32_t ns_flags;
7153 7152
7154 7153 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
7155 7154 if (create) {
7156 7155 ns_flags |= FCTL_NS_CREATE_DEVICE;
7157 7156 }
7158 7157 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
7159 7158 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
7160 7159
7161 7160 if (ns_cmd == NULL) {
7162 7161 return (FC_NOMEM);
7163 7162 }
7164 7163 ns_cmd->ns_gan_index = 0;
7165 7164 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
7166 7165 ns_cmd->ns_cmd_code = NS_GA_NXT;
7167 7166 ns_cmd->ns_gan_max = 0xFFFF;
7168 7167
7169 7168 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
7170 7169 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
7171 7170 }
7172 7171
7173 7172 flags = job->job_flags;
7174 7173 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
7175 7174 job->job_counter = 1;
7176 7175
7177 7176 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
7178 7177 job->job_flags = flags;
7179 7178
7180 7179 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7181 7180 uint16_t max_resid;
7182 7181
7183 7182 /*
7184 7183 * Revert to scanning the NS if NS_GID_PT isn't
7185 7184 * helping us figure out total number of devices.
7186 7185 */
7187 7186 if (job->job_result != FC_SUCCESS ||
7188 7187 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
7189 7188 mutex_enter(&port->fp_mutex);
7190 7189 port->fp_options &= ~FP_NS_SMART_COUNT;
7191 7190 mutex_exit(&port->fp_mutex);
7192 7191
7193 7192 fctl_free_ns_cmd(ns_cmd);
7194 7193 return (fp_ns_get_devcount(port, job, create, sleep));
7195 7194 }
7196 7195
7197 7196 mutex_enter(&port->fp_mutex);
7198 7197 port->fp_total_devices = 1;
7199 7198 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7200 7199 if (max_resid) {
7201 7200 /*
7202 7201 * Since port identifier is 4 bytes and max_resid
7203 7202 * is also in WORDS, max_resid simply indicates
7204 7203 * the total number of port identifiers not
7205 7204 * transferred
7206 7205 */
7207 7206 port->fp_total_devices += max_resid;
7208 7207 }
7209 7208 mutex_exit(&port->fp_mutex);
7210 7209 }
7211 7210 mutex_enter(&port->fp_mutex);
7212 7211 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7213 7212 mutex_exit(&port->fp_mutex);
7214 7213 fctl_free_ns_cmd(ns_cmd);
7215 7214
7216 7215 return (rval);
7217 7216 }
7218 7217
7219 7218 /*
7220 7219 * One heck of a function to serve userland.
7221 7220 */
7222 7221 static int
7223 7222 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7224 7223 {
7225 7224 int rval = 0;
7226 7225 int jcode;
7227 7226 uint32_t ret;
7228 7227 uchar_t open_flag;
7229 7228 fcio_t *kfcio;
7230 7229 job_request_t *job;
7231 7230 boolean_t use32 = B_FALSE;
7232 7231
7233 7232 #ifdef _MULTI_DATAMODEL
7234 7233 switch (ddi_model_convert_from(mode & FMODELS)) {
7235 7234 case DDI_MODEL_ILP32:
7236 7235 use32 = B_TRUE;
7237 7236 break;
7238 7237
7239 7238 case DDI_MODEL_NONE:
7240 7239 default:
7241 7240 break;
7242 7241 }
7243 7242 #endif
7244 7243
7245 7244 mutex_enter(&port->fp_mutex);
7246 7245 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7247 7246 FP_SOFT_IN_UNSOL_CB)) {
7248 7247 fcio->fcio_errno = FC_STATEC_BUSY;
7249 7248 mutex_exit(&port->fp_mutex);
7250 7249 rval = EAGAIN;
7251 7250 if (fp_fcio_copyout(fcio, data, mode)) {
7252 7251 rval = EFAULT;
7253 7252 }
7254 7253 return (rval);
7255 7254 }
7256 7255 open_flag = port->fp_flag;
7257 7256 mutex_exit(&port->fp_mutex);
7258 7257
7259 7258 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7260 7259 fcio->fcio_errno = FC_FAILURE;
7261 7260 rval = EACCES;
7262 7261 if (fp_fcio_copyout(fcio, data, mode)) {
7263 7262 rval = EFAULT;
7264 7263 }
7265 7264 return (rval);
7266 7265 }
7267 7266
7268 7267 /*
7269 7268 * If an exclusive open was demanded during open, don't let
7270 7269 * either innocuous or devil threads to share the file
7271 7270 * descriptor and fire down exclusive access commands
7272 7271 */
7273 7272 mutex_enter(&port->fp_mutex);
7274 7273 if (port->fp_flag & FP_EXCL) {
7275 7274 if (port->fp_flag & FP_EXCL_BUSY) {
7276 7275 mutex_exit(&port->fp_mutex);
7277 7276 fcio->fcio_errno = FC_FAILURE;
7278 7277 return (EBUSY);
7279 7278 }
7280 7279 port->fp_flag |= FP_EXCL_BUSY;
7281 7280 }
7282 7281 mutex_exit(&port->fp_mutex);
7283 7282
7284 7283 fcio->fcio_errno = FC_SUCCESS;
7285 7284
7286 7285 switch (fcio->fcio_cmd) {
7287 7286 case FCIO_GET_HOST_PARAMS: {
7288 7287 fc_port_dev_t *val;
7289 7288 fc_port_dev32_t *val32;
7290 7289 int index;
7291 7290 int lilp_device_count;
7292 7291 fc_lilpmap_t *lilp_map;
7293 7292 uchar_t *alpa_list;
7294 7293
7295 7294 if (use32 == B_TRUE) {
7296 7295 if (fcio->fcio_olen != sizeof (*val32) ||
7297 7296 fcio->fcio_xfer != FCIO_XFER_READ) {
7298 7297 rval = EINVAL;
7299 7298 break;
7300 7299 }
7301 7300 } else {
7302 7301 if (fcio->fcio_olen != sizeof (*val) ||
7303 7302 fcio->fcio_xfer != FCIO_XFER_READ) {
7304 7303 rval = EINVAL;
7305 7304 break;
7306 7305 }
7307 7306 }
7308 7307
7309 7308 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7310 7309
7311 7310 mutex_enter(&port->fp_mutex);
7312 7311 val->dev_did = port->fp_port_id;
7313 7312 val->dev_hard_addr = port->fp_hard_addr;
7314 7313 val->dev_pwwn = port->fp_service_params.nport_ww_name;
7315 7314 val->dev_nwwn = port->fp_service_params.node_ww_name;
7316 7315 val->dev_state = port->fp_state;
7317 7316
7318 7317 lilp_map = &port->fp_lilp_map;
7319 7318 alpa_list = &lilp_map->lilp_alpalist[0];
7320 7319 lilp_device_count = lilp_map->lilp_length;
7321 7320 for (index = 0; index < lilp_device_count; index++) {
7322 7321 uint32_t d_id;
7323 7322
7324 7323 d_id = alpa_list[index];
7325 7324 if (d_id == port->fp_port_id.port_id) {
7326 7325 break;
7327 7326 }
7328 7327 }
7329 7328 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7330 7329
7331 7330 bcopy(port->fp_fc4_types, val->dev_type,
7332 7331 sizeof (port->fp_fc4_types));
7333 7332 mutex_exit(&port->fp_mutex);
7334 7333
7335 7334 if (use32 == B_TRUE) {
7336 7335 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7337 7336
7338 7337 val32->dev_did = val->dev_did;
7339 7338 val32->dev_hard_addr = val->dev_hard_addr;
7340 7339 val32->dev_pwwn = val->dev_pwwn;
7341 7340 val32->dev_nwwn = val->dev_nwwn;
7342 7341 val32->dev_state = val->dev_state;
7343 7342 val32->dev_did.priv_lilp_posit =
7344 7343 val->dev_did.priv_lilp_posit;
7345 7344
7346 7345 bcopy(val->dev_type, val32->dev_type,
7347 7346 sizeof (port->fp_fc4_types));
7348 7347
7349 7348 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7350 7349 fcio->fcio_olen, mode) == 0) {
7351 7350 if (fp_fcio_copyout(fcio, data, mode)) {
7352 7351 rval = EFAULT;
7353 7352 }
7354 7353 } else {
7355 7354 rval = EFAULT;
7356 7355 }
7357 7356
7358 7357 kmem_free(val32, sizeof (*val32));
7359 7358 } else {
7360 7359 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7361 7360 fcio->fcio_olen, mode) == 0) {
7362 7361 if (fp_fcio_copyout(fcio, data, mode)) {
7363 7362 rval = EFAULT;
7364 7363 }
7365 7364 } else {
7366 7365 rval = EFAULT;
7367 7366 }
7368 7367 }
7369 7368
7370 7369 /* need to free "val" here */
7371 7370 kmem_free(val, sizeof (*val));
7372 7371 break;
7373 7372 }
7374 7373
7375 7374 case FCIO_GET_OTHER_ADAPTER_PORTS: {
7376 7375 uint32_t index;
7377 7376 char *tmpPath;
7378 7377 fc_local_port_t *tmpPort;
7379 7378
7380 7379 if (fcio->fcio_olen < MAXPATHLEN ||
7381 7380 fcio->fcio_ilen != sizeof (uint32_t)) {
7382 7381 rval = EINVAL;
7383 7382 break;
7384 7383 }
7385 7384 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7386 7385 rval = EFAULT;
7387 7386 break;
7388 7387 }
7389 7388
7390 7389 tmpPort = fctl_get_adapter_port_by_index(port, index);
7391 7390 if (tmpPort == NULL) {
7392 7391 FP_TRACE(FP_NHEAD1(9, 0),
7393 7392 "User supplied index out of range");
7394 7393 fcio->fcio_errno = FC_BADPORT;
7395 7394 rval = EFAULT;
7396 7395 if (fp_fcio_copyout(fcio, data, mode)) {
7397 7396 rval = EFAULT;
7398 7397 }
7399 7398 break;
7400 7399 }
7401 7400
7402 7401 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7403 7402 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7404 7403 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7405 7404 MAXPATHLEN, mode) == 0) {
7406 7405 if (fp_fcio_copyout(fcio, data, mode)) {
7407 7406 rval = EFAULT;
7408 7407 }
7409 7408 } else {
7410 7409 rval = EFAULT;
7411 7410 }
7412 7411 kmem_free(tmpPath, MAXPATHLEN);
7413 7412 break;
7414 7413 }
7415 7414
7416 7415 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7417 7416 case FCIO_GET_ADAPTER_ATTRIBUTES: {
7418 7417 fc_hba_adapter_attributes_t *val;
7419 7418 fc_hba_adapter_attributes32_t *val32;
7420 7419
7421 7420 if (use32 == B_TRUE) {
7422 7421 if (fcio->fcio_olen < sizeof (*val32) ||
7423 7422 fcio->fcio_xfer != FCIO_XFER_READ) {
7424 7423 rval = EINVAL;
7425 7424 break;
7426 7425 }
7427 7426 } else {
7428 7427 if (fcio->fcio_olen < sizeof (*val) ||
7429 7428 fcio->fcio_xfer != FCIO_XFER_READ) {
7430 7429 rval = EINVAL;
7431 7430 break;
7432 7431 }
7433 7432 }
7434 7433
7435 7434 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7436 7435 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7437 7436 mutex_enter(&port->fp_mutex);
7438 7437 bcopy(port->fp_hba_port_attrs.manufacturer,
7439 7438 val->Manufacturer,
7440 7439 sizeof (val->Manufacturer));
7441 7440 bcopy(port->fp_hba_port_attrs.serial_number,
7442 7441 val->SerialNumber,
7443 7442 sizeof (val->SerialNumber));
7444 7443 bcopy(port->fp_hba_port_attrs.model,
7445 7444 val->Model,
7446 7445 sizeof (val->Model));
7447 7446 bcopy(port->fp_hba_port_attrs.model_description,
7448 7447 val->ModelDescription,
7449 7448 sizeof (val->ModelDescription));
7450 7449 bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7451 7450 port->fp_sym_node_namelen);
7452 7451 bcopy(port->fp_hba_port_attrs.hardware_version,
7453 7452 val->HardwareVersion,
7454 7453 sizeof (val->HardwareVersion));
7455 7454 bcopy(port->fp_hba_port_attrs.option_rom_version,
7456 7455 val->OptionROMVersion,
7457 7456 sizeof (val->OptionROMVersion));
7458 7457 bcopy(port->fp_hba_port_attrs.firmware_version,
7459 7458 val->FirmwareVersion,
7460 7459 sizeof (val->FirmwareVersion));
7461 7460 val->VendorSpecificID =
7462 7461 port->fp_hba_port_attrs.vendor_specific_id;
7463 7462 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7464 7463 &val->NodeWWN.raw_wwn,
7465 7464 sizeof (val->NodeWWN.raw_wwn));
7466 7465
7467 7466
7468 7467 bcopy(port->fp_hba_port_attrs.driver_name,
7469 7468 val->DriverName,
7470 7469 sizeof (val->DriverName));
7471 7470 bcopy(port->fp_hba_port_attrs.driver_version,
7472 7471 val->DriverVersion,
7473 7472 sizeof (val->DriverVersion));
7474 7473 mutex_exit(&port->fp_mutex);
7475 7474
7476 7475 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7477 7476 val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7478 7477 } else {
7479 7478 val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7480 7479 }
7481 7480
7482 7481 if (use32 == B_TRUE) {
7483 7482 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7484 7483 val32->version = val->version;
7485 7484 bcopy(val->Manufacturer, val32->Manufacturer,
7486 7485 sizeof (val->Manufacturer));
7487 7486 bcopy(val->SerialNumber, val32->SerialNumber,
7488 7487 sizeof (val->SerialNumber));
7489 7488 bcopy(val->Model, val32->Model,
7490 7489 sizeof (val->Model));
7491 7490 bcopy(val->ModelDescription, val32->ModelDescription,
7492 7491 sizeof (val->ModelDescription));
7493 7492 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7494 7493 sizeof (val->NodeSymbolicName));
7495 7494 bcopy(val->HardwareVersion, val32->HardwareVersion,
7496 7495 sizeof (val->HardwareVersion));
7497 7496 bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7498 7497 sizeof (val->OptionROMVersion));
7499 7498 bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7500 7499 sizeof (val->FirmwareVersion));
7501 7500 val32->VendorSpecificID = val->VendorSpecificID;
7502 7501 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7503 7502 sizeof (val->NodeWWN.raw_wwn));
7504 7503 bcopy(val->DriverName, val32->DriverName,
7505 7504 sizeof (val->DriverName));
7506 7505 bcopy(val->DriverVersion, val32->DriverVersion,
7507 7506 sizeof (val->DriverVersion));
7508 7507
7509 7508 val32->NumberOfPorts = val->NumberOfPorts;
7510 7509
7511 7510 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7512 7511 fcio->fcio_olen, mode) == 0) {
7513 7512 if (fp_fcio_copyout(fcio, data, mode)) {
7514 7513 rval = EFAULT;
7515 7514 }
7516 7515 } else {
7517 7516 rval = EFAULT;
7518 7517 }
7519 7518
7520 7519 kmem_free(val32, sizeof (*val32));
7521 7520 } else {
7522 7521 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7523 7522 fcio->fcio_olen, mode) == 0) {
7524 7523 if (fp_fcio_copyout(fcio, data, mode)) {
7525 7524 rval = EFAULT;
7526 7525 }
7527 7526 } else {
7528 7527 rval = EFAULT;
7529 7528 }
7530 7529 }
7531 7530
7532 7531 kmem_free(val, sizeof (*val));
7533 7532 break;
7534 7533 }
7535 7534
7536 7535 case FCIO_GET_NPIV_ATTRIBUTES: {
7537 7536 fc_hba_npiv_attributes_t *attrs;
7538 7537
7539 7538 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7540 7539 mutex_enter(&port->fp_mutex);
7541 7540 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7542 7541 &attrs->NodeWWN.raw_wwn,
7543 7542 sizeof (attrs->NodeWWN.raw_wwn));
7544 7543 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7545 7544 &attrs->PortWWN.raw_wwn,
7546 7545 sizeof (attrs->PortWWN.raw_wwn));
7547 7546 mutex_exit(&port->fp_mutex);
7548 7547 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7549 7548 fcio->fcio_olen, mode) == 0) {
7550 7549 if (fp_fcio_copyout(fcio, data, mode)) {
7551 7550 rval = EFAULT;
7552 7551 }
7553 7552 } else {
7554 7553 rval = EFAULT;
7555 7554 }
7556 7555 kmem_free(attrs, sizeof (*attrs));
7557 7556 break;
7558 7557 }
7559 7558
7560 7559 case FCIO_DELETE_NPIV_PORT: {
7561 7560 fc_local_port_t *tmpport;
7562 7561 char ww_pname[17];
7563 7562 la_wwn_t vwwn[1];
7564 7563
7565 7564 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7566 7565 if (ddi_copyin(fcio->fcio_ibuf,
7567 7566 &vwwn, sizeof (la_wwn_t), mode)) {
7568 7567 rval = EFAULT;
7569 7568 break;
7570 7569 }
7571 7570
7572 7571 fc_wwn_to_str(&vwwn[0], ww_pname);
7573 7572 FP_TRACE(FP_NHEAD1(3, 0),
7574 7573 "Delete NPIV Port %s", ww_pname);
7575 7574 tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7576 7575 if (tmpport == NULL) {
7577 7576 FP_TRACE(FP_NHEAD1(3, 0),
7578 7577 "Delete NPIV Port : no found");
7579 7578 rval = EFAULT;
7580 7579 } else {
7581 7580 fc_local_port_t *nextport = tmpport->fp_port_next;
7582 7581 fc_local_port_t *prevport = tmpport->fp_port_prev;
7583 7582 int portlen, portindex, ret;
7584 7583
7585 7584 portlen = sizeof (portindex);
7586 7585 ret = ddi_prop_op(DDI_DEV_T_ANY,
7587 7586 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7588 7587 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7589 7588 (caddr_t)&portindex, &portlen);
7590 7589 if (ret != DDI_SUCCESS) {
7591 7590 rval = EFAULT;
7592 7591 break;
7593 7592 }
7594 7593 if (ndi_devi_offline(tmpport->fp_port_dip,
7595 7594 NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7596 7595 FP_TRACE(FP_NHEAD1(1, 0),
7597 7596 "Delete NPIV Port failed");
7598 7597 mutex_enter(&port->fp_mutex);
7599 7598 tmpport->fp_npiv_state = 0;
7600 7599 mutex_exit(&port->fp_mutex);
7601 7600 rval = EFAULT;
7602 7601 } else {
7603 7602 mutex_enter(&port->fp_mutex);
7604 7603 nextport->fp_port_prev = prevport;
7605 7604 prevport->fp_port_next = nextport;
7606 7605 if (port == port->fp_port_next) {
7607 7606 port->fp_port_next =
7608 7607 port->fp_port_prev = NULL;
7609 7608 }
7610 7609 port->fp_npiv_portnum--;
7611 7610 FP_TRACE(FP_NHEAD1(3, 0),
7612 7611 "Delete NPIV Port %d", portindex);
7613 7612 port->fp_npiv_portindex[portindex-1] = 0;
7614 7613 mutex_exit(&port->fp_mutex);
7615 7614 }
7616 7615 }
7617 7616 break;
7618 7617 }
7619 7618
7620 7619 case FCIO_CREATE_NPIV_PORT: {
7621 7620 char ww_nname[17], ww_pname[17];
7622 7621 la_npiv_create_entry_t entrybuf;
7623 7622 uint32_t vportindex = 0;
7624 7623 int npiv_ret = 0;
7625 7624 char *portname, *fcaname;
7626 7625
7627 7626 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7628 7627 (void) ddi_pathname(port->fp_port_dip, portname);
7629 7628 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7630 7629 (void) ddi_pathname(port->fp_fca_dip, fcaname);
7631 7630 FP_TRACE(FP_NHEAD1(1, 0),
7632 7631 "Create NPIV port %s %s %s", portname, fcaname,
7633 7632 ddi_driver_name(port->fp_fca_dip));
7634 7633 kmem_free(portname, MAXPATHLEN);
7635 7634 kmem_free(fcaname, MAXPATHLEN);
7636 7635 if (ddi_copyin(fcio->fcio_ibuf,
7637 7636 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7638 7637 rval = EFAULT;
7639 7638 break;
7640 7639 }
7641 7640
7642 7641 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7643 7642 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7644 7643 vportindex = entrybuf.vindex;
7645 7644 FP_TRACE(FP_NHEAD1(3, 0),
7646 7645 "Create NPIV Port %s %s %d",
7647 7646 ww_nname, ww_pname, vportindex);
7648 7647
7649 7648 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7650 7649 rval = EFAULT;
7651 7650 break;
7652 7651 }
7653 7652 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7654 7653 port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7655 7654 if (npiv_ret == NDI_SUCCESS) {
7656 7655 mutex_enter(&port->fp_mutex);
7657 7656 port->fp_npiv_portnum++;
7658 7657 mutex_exit(&port->fp_mutex);
7659 7658 if (fp_copyout((void *)&vportindex,
7660 7659 (void *)fcio->fcio_obuf,
7661 7660 fcio->fcio_olen, mode) == 0) {
7662 7661 if (fp_fcio_copyout(fcio, data, mode)) {
7663 7662 rval = EFAULT;
7664 7663 }
7665 7664 } else {
7666 7665 rval = EFAULT;
7667 7666 }
7668 7667 } else {
7669 7668 rval = EFAULT;
7670 7669 }
7671 7670 FP_TRACE(FP_NHEAD1(3, 0),
7672 7671 "Create NPIV Port %d %d", npiv_ret, vportindex);
7673 7672 break;
7674 7673 }
7675 7674
7676 7675 case FCIO_GET_NPIV_PORT_LIST: {
7677 7676 fc_hba_npiv_port_list_t *list;
7678 7677 int count;
7679 7678
7680 7679 if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7681 7680 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7682 7681 rval = EINVAL;
7683 7682 break;
7684 7683 }
7685 7684
7686 7685 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7687 7686 list->version = FC_HBA_LIST_VERSION;
7688 7687
7689 7688 count = (fcio->fcio_olen -
7690 7689 (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN + 1;
7691 7690 if (port->fp_npiv_portnum > count) {
7692 7691 list->numAdapters = port->fp_npiv_portnum;
7693 7692 } else {
7694 7693 /* build npiv port list */
7695 7694 count = fc_ulp_get_npiv_port_list(port,
7696 7695 (char *)list->hbaPaths);
7697 7696 if (count < 0) {
7698 7697 rval = ENXIO;
7699 7698 FP_TRACE(FP_NHEAD1(1, 0),
7700 7699 "Build NPIV Port List error");
7701 7700 kmem_free(list, fcio->fcio_olen);
7702 7701 break;
7703 7702 }
7704 7703 list->numAdapters = count;
7705 7704 }
7706 7705
7707 7706 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7708 7707 fcio->fcio_olen, mode) == 0) {
7709 7708 if (fp_fcio_copyout(fcio, data, mode)) {
7710 7709 FP_TRACE(FP_NHEAD1(1, 0),
7711 7710 "Copy NPIV Port data error");
7712 7711 rval = EFAULT;
7713 7712 }
7714 7713 } else {
7715 7714 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7716 7715 rval = EFAULT;
7717 7716 }
7718 7717 kmem_free(list, fcio->fcio_olen);
7719 7718 break;
7720 7719 }
7721 7720
7722 7721 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7723 7722 fc_hba_port_npiv_attributes_t *val;
7724 7723
7725 7724 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7726 7725 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7727 7726
7728 7727 mutex_enter(&port->fp_mutex);
7729 7728 val->npivflag = port->fp_npiv_flag;
7730 7729 val->lastChange = port->fp_last_change;
7731 7730 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7732 7731 &val->PortWWN.raw_wwn,
7733 7732 sizeof (val->PortWWN.raw_wwn));
7734 7733 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7735 7734 &val->NodeWWN.raw_wwn,
7736 7735 sizeof (val->NodeWWN.raw_wwn));
7737 7736 mutex_exit(&port->fp_mutex);
7738 7737
7739 7738 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7740 7739 if (port->fp_npiv_type != FC_NPIV_PORT) {
7741 7740 val->MaxNumberOfNPIVPorts =
7742 7741 port->fp_fca_tran->fca_num_npivports;
7743 7742 } else {
7744 7743 val->MaxNumberOfNPIVPorts = 0;
7745 7744 }
7746 7745
7747 7746 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7748 7747 fcio->fcio_olen, mode) == 0) {
7749 7748 if (fp_fcio_copyout(fcio, data, mode)) {
7750 7749 rval = EFAULT;
7751 7750 }
7752 7751 } else {
7753 7752 rval = EFAULT;
7754 7753 }
7755 7754 kmem_free(val, sizeof (*val));
7756 7755 break;
7757 7756 }
7758 7757
7759 7758 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7760 7759 fc_hba_port_attributes_t *val;
7761 7760 fc_hba_port_attributes32_t *val32;
7762 7761
7763 7762 if (use32 == B_TRUE) {
7764 7763 if (fcio->fcio_olen < sizeof (*val32) ||
7765 7764 fcio->fcio_xfer != FCIO_XFER_READ) {
7766 7765 rval = EINVAL;
7767 7766 break;
7768 7767 }
7769 7768 } else {
7770 7769 if (fcio->fcio_olen < sizeof (*val) ||
7771 7770 fcio->fcio_xfer != FCIO_XFER_READ) {
7772 7771 rval = EINVAL;
7773 7772 break;
7774 7773 }
7775 7774 }
7776 7775
7777 7776 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7778 7777 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7779 7778 mutex_enter(&port->fp_mutex);
7780 7779 val->lastChange = port->fp_last_change;
7781 7780 val->fp_minor = port->fp_instance;
7782 7781
7783 7782 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7784 7783 &val->PortWWN.raw_wwn,
7785 7784 sizeof (val->PortWWN.raw_wwn));
7786 7785 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7787 7786 &val->NodeWWN.raw_wwn,
7788 7787 sizeof (val->NodeWWN.raw_wwn));
7789 7788 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7790 7789 sizeof (val->FabricName.raw_wwn));
7791 7790
7792 7791 val->PortFcId = port->fp_port_id.port_id;
7793 7792
7794 7793 switch (FC_PORT_STATE_MASK(port->fp_state)) {
7795 7794 case FC_STATE_OFFLINE:
7796 7795 val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7797 7796 break;
7798 7797 case FC_STATE_ONLINE:
7799 7798 case FC_STATE_LOOP:
7800 7799 case FC_STATE_NAMESERVICE:
7801 7800 val->PortState = FC_HBA_PORTSTATE_ONLINE;
7802 7801 break;
7803 7802 default:
7804 7803 val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7805 7804 break;
7806 7805 }
7807 7806
7808 7807 /* Translate from LV to FC-HBA port type codes */
7809 7808 switch (port->fp_port_type.port_type) {
7810 7809 case FC_NS_PORT_N:
7811 7810 val->PortType = FC_HBA_PORTTYPE_NPORT;
7812 7811 break;
7813 7812 case FC_NS_PORT_NL:
7814 7813 /* Actually means loop for us */
7815 7814 val->PortType = FC_HBA_PORTTYPE_LPORT;
7816 7815 break;
7817 7816 case FC_NS_PORT_F:
7818 7817 val->PortType = FC_HBA_PORTTYPE_FPORT;
7819 7818 break;
7820 7819 case FC_NS_PORT_FL:
7821 7820 val->PortType = FC_HBA_PORTTYPE_FLPORT;
7822 7821 break;
7823 7822 case FC_NS_PORT_E:
7824 7823 val->PortType = FC_HBA_PORTTYPE_EPORT;
7825 7824 break;
7826 7825 default:
7827 7826 val->PortType = FC_HBA_PORTTYPE_OTHER;
7828 7827 break;
7829 7828 }
7830 7829
7831 7830
7832 7831 /*
7833 7832 * If fp has decided that the topology is public loop,
7834 7833 * we will indicate that using the appropriate
7835 7834 * FC HBA API constant.
7836 7835 */
7837 7836 switch (port->fp_topology) {
7838 7837 case FC_TOP_PUBLIC_LOOP:
7839 7838 val->PortType = FC_HBA_PORTTYPE_NLPORT;
7840 7839 break;
7841 7840
7842 7841 case FC_TOP_PT_PT:
7843 7842 val->PortType = FC_HBA_PORTTYPE_PTP;
7844 7843 break;
7845 7844
7846 7845 case FC_TOP_UNKNOWN:
7847 7846 /*
7848 7847 * This should cover the case where nothing is connected
7849 7848 * to the port. Crystal+ is p'bly an exception here.
7850 7849 * For Crystal+, port 0 will come up as private loop
7851 7850 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7852 7851 * nothing is connected to it.
7853 7852 * Current plan is to let userland handle this.
7854 7853 */
7855 7854 if (port->fp_bind_state == FC_STATE_OFFLINE) {
7856 7855 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7857 7856 }
7858 7857 break;
7859 7858
7860 7859 default:
7861 7860 /*
7862 7861 * Do Nothing.
7863 7862 * Unused:
7864 7863 * val->PortType = FC_HBA_PORTTYPE_GPORT;
7865 7864 */
7866 7865 break;
7867 7866 }
7868 7867
7869 7868 val->PortSupportedClassofService =
7870 7869 port->fp_hba_port_attrs.supported_cos;
7871 7870 val->PortSupportedFc4Types[0] = 0;
7872 7871 bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7873 7872 sizeof (val->PortActiveFc4Types));
7874 7873 bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7875 7874 port->fp_sym_port_namelen);
7876 7875 val->PortSupportedSpeed =
7877 7876 port->fp_hba_port_attrs.supported_speed;
7878 7877
7879 7878 switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7880 7879 case FC_STATE_1GBIT_SPEED:
7881 7880 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7882 7881 break;
7883 7882 case FC_STATE_2GBIT_SPEED:
7884 7883 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7885 7884 break;
7886 7885 case FC_STATE_4GBIT_SPEED:
7887 7886 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7888 7887 break;
7889 7888 case FC_STATE_8GBIT_SPEED:
7890 7889 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7891 7890 break;
7892 7891 case FC_STATE_10GBIT_SPEED:
7893 7892 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7894 7893 break;
7895 7894 case FC_STATE_16GBIT_SPEED:
7896 7895 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7897 7896 break;
7898 7897 default:
7899 7898 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7900 7899 break;
7901 7900 }
7902 7901 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7903 7902 val->NumberofDiscoveredPorts = port->fp_dev_count;
7904 7903 mutex_exit(&port->fp_mutex);
7905 7904
7906 7905 if (use32 == B_TRUE) {
7907 7906 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7908 7907 val32->version = val->version;
7909 7908 val32->lastChange = val->lastChange;
7910 7909 val32->fp_minor = val->fp_minor;
7911 7910
7912 7911 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7913 7912 sizeof (val->PortWWN.raw_wwn));
7914 7913 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7915 7914 sizeof (val->NodeWWN.raw_wwn));
7916 7915 val32->PortFcId = val->PortFcId;
7917 7916 val32->PortState = val->PortState;
7918 7917 val32->PortType = val->PortType;
7919 7918
7920 7919 val32->PortSupportedClassofService =
7921 7920 val->PortSupportedClassofService;
7922 7921 bcopy(val->PortActiveFc4Types,
7923 7922 val32->PortActiveFc4Types,
7924 7923 sizeof (val->PortActiveFc4Types));
7925 7924 bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7926 7925 sizeof (val->PortSymbolicName));
7927 7926 bcopy(&val->FabricName, &val32->FabricName,
7928 7927 sizeof (val->FabricName.raw_wwn));
7929 7928 val32->PortSupportedSpeed = val->PortSupportedSpeed;
7930 7929 val32->PortSpeed = val->PortSpeed;
7931 7930
7932 7931 val32->PortMaxFrameSize = val->PortMaxFrameSize;
7933 7932 val32->NumberofDiscoveredPorts =
7934 7933 val->NumberofDiscoveredPorts;
7935 7934
7936 7935 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7937 7936 fcio->fcio_olen, mode) == 0) {
7938 7937 if (fp_fcio_copyout(fcio, data, mode)) {
7939 7938 rval = EFAULT;
7940 7939 }
7941 7940 } else {
7942 7941 rval = EFAULT;
7943 7942 }
7944 7943
7945 7944 kmem_free(val32, sizeof (*val32));
7946 7945 } else {
7947 7946 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7948 7947 fcio->fcio_olen, mode) == 0) {
7949 7948 if (fp_fcio_copyout(fcio, data, mode)) {
7950 7949 rval = EFAULT;
7951 7950 }
7952 7951 } else {
7953 7952 rval = EFAULT;
7954 7953 }
7955 7954 }
7956 7955
7957 7956 kmem_free(val, sizeof (*val));
7958 7957 break;
7959 7958 }
7960 7959
7961 7960 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7962 7961 fc_hba_port_attributes_t *val;
7963 7962 fc_hba_port_attributes32_t *val32;
7964 7963 uint32_t index = 0;
7965 7964 fc_remote_port_t *tmp_pd;
7966 7965
7967 7966 if (use32 == B_TRUE) {
7968 7967 if (fcio->fcio_olen < sizeof (*val32) ||
7969 7968 fcio->fcio_xfer != FCIO_XFER_READ) {
7970 7969 rval = EINVAL;
7971 7970 break;
7972 7971 }
7973 7972 } else {
7974 7973 if (fcio->fcio_olen < sizeof (*val) ||
7975 7974 fcio->fcio_xfer != FCIO_XFER_READ) {
7976 7975 rval = EINVAL;
7977 7976 break;
7978 7977 }
7979 7978 }
7980 7979
7981 7980 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7982 7981 rval = EFAULT;
7983 7982 break;
7984 7983 }
7985 7984
7986 7985 if (index >= port->fp_dev_count) {
7987 7986 FP_TRACE(FP_NHEAD1(9, 0),
7988 7987 "User supplied index out of range");
7989 7988 fcio->fcio_errno = FC_OUTOFBOUNDS;
7990 7989 rval = EINVAL;
7991 7990 if (fp_fcio_copyout(fcio, data, mode)) {
7992 7991 rval = EFAULT;
7993 7992 }
7994 7993 break;
7995 7994 }
7996 7995
7997 7996 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7998 7997 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7999 7998
8000 7999 mutex_enter(&port->fp_mutex);
8001 8000 tmp_pd = fctl_lookup_pd_by_index(port, index);
8002 8001
8003 8002 if (tmp_pd == NULL) {
8004 8003 fcio->fcio_errno = FC_BADPORT;
8005 8004 rval = EINVAL;
8006 8005 } else {
8007 8006 val->lastChange = port->fp_last_change;
8008 8007 val->fp_minor = port->fp_instance;
8009 8008
8010 8009 mutex_enter(&tmp_pd->pd_mutex);
8011 8010 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8012 8011 &val->PortWWN.raw_wwn,
8013 8012 sizeof (val->PortWWN.raw_wwn));
8014 8013 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8015 8014 &val->NodeWWN.raw_wwn,
8016 8015 sizeof (val->NodeWWN.raw_wwn));
8017 8016 val->PortFcId = tmp_pd->pd_port_id.port_id;
8018 8017 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8019 8018 tmp_pd->pd_spn_len);
8020 8019 val->PortSupportedClassofService = tmp_pd->pd_cos;
8021 8020 /*
8022 8021 * we will assume the sizeof these pd_fc4types and
8023 8022 * portActiveFc4Types will remain the same. we could
8024 8023 * add in a check for it, but we decided it was unneeded
8025 8024 */
8026 8025 bcopy((caddr_t)tmp_pd->pd_fc4types,
8027 8026 val->PortActiveFc4Types,
8028 8027 sizeof (tmp_pd->pd_fc4types));
8029 8028 val->PortState =
8030 8029 fp_map_remote_port_state(tmp_pd->pd_state);
8031 8030 mutex_exit(&tmp_pd->pd_mutex);
8032 8031
8033 8032 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8034 8033 val->PortSupportedFc4Types[0] = 0;
8035 8034 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8036 8035 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8037 8036 val->PortMaxFrameSize = 0;
8038 8037 val->NumberofDiscoveredPorts = 0;
8039 8038
8040 8039 if (use32 == B_TRUE) {
8041 8040 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8042 8041 val32->version = val->version;
8043 8042 val32->lastChange = val->lastChange;
8044 8043 val32->fp_minor = val->fp_minor;
8045 8044
8046 8045 bcopy(&val->PortWWN.raw_wwn,
8047 8046 &val32->PortWWN.raw_wwn,
8048 8047 sizeof (val->PortWWN.raw_wwn));
8049 8048 bcopy(&val->NodeWWN.raw_wwn,
8050 8049 &val32->NodeWWN.raw_wwn,
8051 8050 sizeof (val->NodeWWN.raw_wwn));
8052 8051 val32->PortFcId = val->PortFcId;
8053 8052 bcopy(val->PortSymbolicName,
8054 8053 val32->PortSymbolicName,
8055 8054 sizeof (val->PortSymbolicName));
8056 8055 val32->PortSupportedClassofService =
8057 8056 val->PortSupportedClassofService;
8058 8057 bcopy(val->PortActiveFc4Types,
8059 8058 val32->PortActiveFc4Types,
8060 8059 sizeof (tmp_pd->pd_fc4types));
8061 8060
8062 8061 val32->PortType = val->PortType;
8063 8062 val32->PortState = val->PortState;
8064 8063 val32->PortSupportedFc4Types[0] =
8065 8064 val->PortSupportedFc4Types[0];
8066 8065 val32->PortSupportedSpeed =
8067 8066 val->PortSupportedSpeed;
8068 8067 val32->PortSpeed = val->PortSpeed;
8069 8068 val32->PortMaxFrameSize =
8070 8069 val->PortMaxFrameSize;
8071 8070 val32->NumberofDiscoveredPorts =
8072 8071 val->NumberofDiscoveredPorts;
8073 8072
8074 8073 if (fp_copyout((void *)val32,
8075 8074 (void *)fcio->fcio_obuf,
8076 8075 fcio->fcio_olen, mode) == 0) {
8077 8076 if (fp_fcio_copyout(fcio,
8078 8077 data, mode)) {
8079 8078 rval = EFAULT;
8080 8079 }
8081 8080 } else {
8082 8081 rval = EFAULT;
8083 8082 }
8084 8083
8085 8084 kmem_free(val32, sizeof (*val32));
8086 8085 } else {
8087 8086 if (fp_copyout((void *)val,
8088 8087 (void *)fcio->fcio_obuf,
8089 8088 fcio->fcio_olen, mode) == 0) {
8090 8089 if (fp_fcio_copyout(fcio, data, mode)) {
8091 8090 rval = EFAULT;
8092 8091 }
8093 8092 } else {
8094 8093 rval = EFAULT;
8095 8094 }
8096 8095 }
8097 8096 }
8098 8097
8099 8098 mutex_exit(&port->fp_mutex);
8100 8099 kmem_free(val, sizeof (*val));
8101 8100 break;
8102 8101 }
8103 8102
8104 8103 case FCIO_GET_PORT_ATTRIBUTES: {
8105 8104 fc_hba_port_attributes_t *val;
8106 8105 fc_hba_port_attributes32_t *val32;
8107 8106 la_wwn_t wwn;
8108 8107 fc_remote_port_t *tmp_pd;
8109 8108
8110 8109 if (use32 == B_TRUE) {
8111 8110 if (fcio->fcio_olen < sizeof (*val32) ||
8112 8111 fcio->fcio_xfer != FCIO_XFER_READ) {
8113 8112 rval = EINVAL;
8114 8113 break;
8115 8114 }
8116 8115 } else {
8117 8116 if (fcio->fcio_olen < sizeof (*val) ||
8118 8117 fcio->fcio_xfer != FCIO_XFER_READ) {
8119 8118 rval = EINVAL;
8120 8119 break;
8121 8120 }
8122 8121 }
8123 8122
8124 8123 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8125 8124 rval = EFAULT;
8126 8125 break;
8127 8126 }
8128 8127
8129 8128 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8130 8129 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8131 8130
8132 8131 mutex_enter(&port->fp_mutex);
8133 8132 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8134 8133 val->lastChange = port->fp_last_change;
8135 8134 val->fp_minor = port->fp_instance;
8136 8135 mutex_exit(&port->fp_mutex);
8137 8136
8138 8137 if (tmp_pd == NULL) {
8139 8138 fcio->fcio_errno = FC_BADWWN;
8140 8139 rval = EINVAL;
8141 8140 } else {
8142 8141 mutex_enter(&tmp_pd->pd_mutex);
8143 8142 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8144 8143 &val->PortWWN.raw_wwn,
8145 8144 sizeof (val->PortWWN.raw_wwn));
8146 8145 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8147 8146 &val->NodeWWN.raw_wwn,
8148 8147 sizeof (val->NodeWWN.raw_wwn));
8149 8148 val->PortFcId = tmp_pd->pd_port_id.port_id;
8150 8149 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8151 8150 tmp_pd->pd_spn_len);
8152 8151 val->PortSupportedClassofService = tmp_pd->pd_cos;
8153 8152 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8154 8153 val->PortState =
8155 8154 fp_map_remote_port_state(tmp_pd->pd_state);
8156 8155 val->PortSupportedFc4Types[0] = 0;
8157 8156 /*
8158 8157 * we will assume the sizeof these pd_fc4types and
8159 8158 * portActiveFc4Types will remain the same. we could
8160 8159 * add in a check for it, but we decided it was unneeded
8161 8160 */
8162 8161 bcopy((caddr_t)tmp_pd->pd_fc4types,
8163 8162 val->PortActiveFc4Types,
8164 8163 sizeof (tmp_pd->pd_fc4types));
8165 8164 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8166 8165 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8167 8166 val->PortMaxFrameSize = 0;
8168 8167 val->NumberofDiscoveredPorts = 0;
8169 8168 mutex_exit(&tmp_pd->pd_mutex);
8170 8169
8171 8170 if (use32 == B_TRUE) {
8172 8171 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8173 8172 val32->version = val->version;
8174 8173 val32->lastChange = val->lastChange;
8175 8174 val32->fp_minor = val->fp_minor;
8176 8175 bcopy(&val->PortWWN.raw_wwn,
8177 8176 &val32->PortWWN.raw_wwn,
8178 8177 sizeof (val->PortWWN.raw_wwn));
8179 8178 bcopy(&val->NodeWWN.raw_wwn,
8180 8179 &val32->NodeWWN.raw_wwn,
8181 8180 sizeof (val->NodeWWN.raw_wwn));
8182 8181 val32->PortFcId = val->PortFcId;
8183 8182 bcopy(val->PortSymbolicName,
8184 8183 val32->PortSymbolicName,
8185 8184 sizeof (val->PortSymbolicName));
8186 8185 val32->PortSupportedClassofService =
8187 8186 val->PortSupportedClassofService;
8188 8187 val32->PortType = val->PortType;
8189 8188 val32->PortState = val->PortState;
8190 8189 val32->PortSupportedFc4Types[0] =
8191 8190 val->PortSupportedFc4Types[0];
8192 8191 bcopy(val->PortActiveFc4Types,
8193 8192 val32->PortActiveFc4Types,
8194 8193 sizeof (tmp_pd->pd_fc4types));
8195 8194 val32->PortSupportedSpeed =
8196 8195 val->PortSupportedSpeed;
8197 8196 val32->PortSpeed = val->PortSpeed;
8198 8197 val32->PortMaxFrameSize = val->PortMaxFrameSize;
8199 8198 val32->NumberofDiscoveredPorts =
8200 8199 val->NumberofDiscoveredPorts;
8201 8200
8202 8201 if (fp_copyout((void *)val32,
8203 8202 (void *)fcio->fcio_obuf,
8204 8203 fcio->fcio_olen, mode) == 0) {
8205 8204 if (fp_fcio_copyout(fcio, data, mode)) {
8206 8205 rval = EFAULT;
8207 8206 }
8208 8207 } else {
8209 8208 rval = EFAULT;
8210 8209 }
8211 8210
8212 8211 kmem_free(val32, sizeof (*val32));
8213 8212 } else {
8214 8213 if (fp_copyout((void *)val,
8215 8214 (void *)fcio->fcio_obuf,
8216 8215 fcio->fcio_olen, mode) == 0) {
8217 8216 if (fp_fcio_copyout(fcio, data, mode)) {
8218 8217 rval = EFAULT;
8219 8218 }
8220 8219 } else {
8221 8220 rval = EFAULT;
8222 8221 }
8223 8222 }
8224 8223 }
8225 8224 kmem_free(val, sizeof (*val));
8226 8225 break;
8227 8226 }
8228 8227
8229 8228 case FCIO_GET_NUM_DEVS: {
8230 8229 int num_devices;
8231 8230
8232 8231 if (fcio->fcio_olen != sizeof (num_devices) ||
8233 8232 fcio->fcio_xfer != FCIO_XFER_READ) {
8234 8233 rval = EINVAL;
8235 8234 break;
8236 8235 }
8237 8236
8238 8237 mutex_enter(&port->fp_mutex);
8239 8238 switch (port->fp_topology) {
8240 8239 case FC_TOP_PRIVATE_LOOP:
8241 8240 case FC_TOP_PT_PT:
8242 8241 num_devices = port->fp_total_devices;
8243 8242 fcio->fcio_errno = FC_SUCCESS;
8244 8243 break;
8245 8244
8246 8245 case FC_TOP_PUBLIC_LOOP:
8247 8246 case FC_TOP_FABRIC:
8248 8247 mutex_exit(&port->fp_mutex);
8249 8248 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8250 8249 NULL, KM_SLEEP);
8251 8250 ASSERT(job != NULL);
8252 8251
8253 8252 /*
8254 8253 * In FC-GS-2 the Name Server doesn't send out
8255 8254 * RSCNs for any Name Server Database updates
8256 8255 * When it is finally fixed there is no need
8257 8256 * to probe as below and should be removed.
8258 8257 */
8259 8258 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8260 8259 fctl_dealloc_job(job);
8261 8260
8262 8261 mutex_enter(&port->fp_mutex);
8263 8262 num_devices = port->fp_total_devices;
8264 8263 fcio->fcio_errno = FC_SUCCESS;
8265 8264 break;
8266 8265
8267 8266 case FC_TOP_NO_NS:
8268 8267 /* FALLTHROUGH */
8269 8268 case FC_TOP_UNKNOWN:
8270 8269 /* FALLTHROUGH */
8271 8270 default:
8272 8271 num_devices = 0;
8273 8272 fcio->fcio_errno = FC_SUCCESS;
8274 8273 break;
8275 8274 }
8276 8275 mutex_exit(&port->fp_mutex);
8277 8276
8278 8277 if (fp_copyout((void *)&num_devices,
8279 8278 (void *)fcio->fcio_obuf, fcio->fcio_olen,
8280 8279 mode) == 0) {
8281 8280 if (fp_fcio_copyout(fcio, data, mode)) {
8282 8281 rval = EFAULT;
8283 8282 }
8284 8283 } else {
8285 8284 rval = EFAULT;
8286 8285 }
8287 8286 break;
8288 8287 }
8289 8288
8290 8289 case FCIO_GET_DEV_LIST: {
8291 8290 int num_devices;
8292 8291 int new_count;
8293 8292 int map_size;
8294 8293
8295 8294 if (fcio->fcio_xfer != FCIO_XFER_READ ||
8296 8295 fcio->fcio_alen != sizeof (new_count)) {
8297 8296 rval = EINVAL;
8298 8297 break;
8299 8298 }
8300 8299
8301 8300 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8302 8301
8303 8302 mutex_enter(&port->fp_mutex);
8304 8303 if (num_devices < port->fp_total_devices) {
8305 8304 fcio->fcio_errno = FC_TOOMANY;
8306 8305 new_count = port->fp_total_devices;
8307 8306 mutex_exit(&port->fp_mutex);
8308 8307
8309 8308 if (fp_copyout((void *)&new_count,
8310 8309 (void *)fcio->fcio_abuf,
8311 8310 sizeof (new_count), mode)) {
8312 8311 rval = EFAULT;
8313 8312 break;
8314 8313 }
8315 8314
8316 8315 if (fp_fcio_copyout(fcio, data, mode)) {
8317 8316 rval = EFAULT;
8318 8317 break;
8319 8318 }
8320 8319 rval = EINVAL;
8321 8320 break;
8322 8321 }
8323 8322
8324 8323 if (port->fp_total_devices <= 0) {
8325 8324 fcio->fcio_errno = FC_NO_MAP;
8326 8325 new_count = port->fp_total_devices;
8327 8326 mutex_exit(&port->fp_mutex);
8328 8327
8329 8328 if (fp_copyout((void *)&new_count,
8330 8329 (void *)fcio->fcio_abuf,
8331 8330 sizeof (new_count), mode)) {
8332 8331 rval = EFAULT;
8333 8332 break;
8334 8333 }
8335 8334
8336 8335 if (fp_fcio_copyout(fcio, data, mode)) {
8337 8336 rval = EFAULT;
8338 8337 break;
8339 8338 }
8340 8339 rval = EINVAL;
8341 8340 break;
8342 8341 }
8343 8342
8344 8343 switch (port->fp_topology) {
8345 8344 case FC_TOP_PRIVATE_LOOP:
8346 8345 if (fp_fillout_loopmap(port, fcio,
8347 8346 mode) != FC_SUCCESS) {
8348 8347 rval = EFAULT;
8349 8348 break;
8350 8349 }
8351 8350 if (fp_fcio_copyout(fcio, data, mode)) {
8352 8351 rval = EFAULT;
8353 8352 }
8354 8353 break;
8355 8354
8356 8355 case FC_TOP_PT_PT:
8357 8356 if (fp_fillout_p2pmap(port, fcio,
8358 8357 mode) != FC_SUCCESS) {
8359 8358 rval = EFAULT;
8360 8359 break;
8361 8360 }
8362 8361 if (fp_fcio_copyout(fcio, data, mode)) {
8363 8362 rval = EFAULT;
8364 8363 }
8365 8364 break;
8366 8365
8367 8366 case FC_TOP_PUBLIC_LOOP:
8368 8367 case FC_TOP_FABRIC: {
8369 8368 fctl_ns_req_t *ns_cmd;
8370 8369
8371 8370 map_size =
8372 8371 sizeof (fc_port_dev_t) * port->fp_total_devices;
8373 8372
8374 8373 mutex_exit(&port->fp_mutex);
8375 8374
8376 8375 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8377 8376 sizeof (ns_resp_gan_t), map_size,
8378 8377 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8379 8378 KM_SLEEP);
8380 8379 ASSERT(ns_cmd != NULL);
8381 8380
8382 8381 ns_cmd->ns_gan_index = 0;
8383 8382 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8384 8383 ns_cmd->ns_cmd_code = NS_GA_NXT;
8385 8384 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8386 8385
8387 8386 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8388 8387 NULL, KM_SLEEP);
8389 8388 ASSERT(job != NULL);
8390 8389
8391 8390 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8392 8391
8393 8392 if (ret != FC_SUCCESS ||
8394 8393 job->job_result != FC_SUCCESS) {
8395 8394 fctl_free_ns_cmd(ns_cmd);
8396 8395
8397 8396 fcio->fcio_errno = job->job_result;
8398 8397 new_count = 0;
8399 8398 if (fp_copyout((void *)&new_count,
8400 8399 (void *)fcio->fcio_abuf,
8401 8400 sizeof (new_count), mode)) {
8402 8401 fctl_dealloc_job(job);
8403 8402 mutex_enter(&port->fp_mutex);
8404 8403 rval = EFAULT;
8405 8404 break;
8406 8405 }
8407 8406
8408 8407 if (fp_fcio_copyout(fcio, data, mode)) {
8409 8408 fctl_dealloc_job(job);
8410 8409 mutex_enter(&port->fp_mutex);
8411 8410 rval = EFAULT;
8412 8411 break;
8413 8412 }
8414 8413 rval = EIO;
8415 8414 mutex_enter(&port->fp_mutex);
8416 8415 break;
8417 8416 }
8418 8417 fctl_dealloc_job(job);
8419 8418
8420 8419 new_count = ns_cmd->ns_gan_index;
8421 8420 if (fp_copyout((void *)&new_count,
8422 8421 (void *)fcio->fcio_abuf, sizeof (new_count),
8423 8422 mode)) {
8424 8423 rval = EFAULT;
8425 8424 fctl_free_ns_cmd(ns_cmd);
8426 8425 mutex_enter(&port->fp_mutex);
8427 8426 break;
8428 8427 }
8429 8428
8430 8429 if (fp_copyout((void *)ns_cmd->ns_data_buf,
8431 8430 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8432 8431 ns_cmd->ns_gan_index, mode)) {
8433 8432 rval = EFAULT;
8434 8433 fctl_free_ns_cmd(ns_cmd);
8435 8434 mutex_enter(&port->fp_mutex);
8436 8435 break;
8437 8436 }
8438 8437 fctl_free_ns_cmd(ns_cmd);
8439 8438
8440 8439 if (fp_fcio_copyout(fcio, data, mode)) {
8441 8440 rval = EFAULT;
8442 8441 }
8443 8442 mutex_enter(&port->fp_mutex);
8444 8443 break;
8445 8444 }
8446 8445
8447 8446 case FC_TOP_NO_NS:
8448 8447 /* FALLTHROUGH */
8449 8448 case FC_TOP_UNKNOWN:
8450 8449 /* FALLTHROUGH */
8451 8450 default:
8452 8451 fcio->fcio_errno = FC_NO_MAP;
8453 8452 num_devices = port->fp_total_devices;
8454 8453
8455 8454 if (fp_copyout((void *)&new_count,
8456 8455 (void *)fcio->fcio_abuf,
8457 8456 sizeof (new_count), mode)) {
8458 8457 rval = EFAULT;
8459 8458 break;
8460 8459 }
8461 8460
8462 8461 if (fp_fcio_copyout(fcio, data, mode)) {
8463 8462 rval = EFAULT;
8464 8463 break;
8465 8464 }
8466 8465 rval = EINVAL;
8467 8466 break;
8468 8467 }
8469 8468 mutex_exit(&port->fp_mutex);
8470 8469 break;
8471 8470 }
8472 8471
8473 8472 case FCIO_GET_SYM_PNAME: {
8474 8473 rval = ENOTSUP;
8475 8474 break;
8476 8475 }
8477 8476
8478 8477 case FCIO_GET_SYM_NNAME: {
8479 8478 rval = ENOTSUP;
8480 8479 break;
8481 8480 }
8482 8481
8483 8482 case FCIO_SET_SYM_PNAME: {
8484 8483 rval = ENOTSUP;
8485 8484 break;
8486 8485 }
8487 8486
8488 8487 case FCIO_SET_SYM_NNAME: {
8489 8488 rval = ENOTSUP;
8490 8489 break;
8491 8490 }
8492 8491
8493 8492 case FCIO_GET_LOGI_PARAMS: {
8494 8493 la_wwn_t pwwn;
8495 8494 la_wwn_t *my_pwwn;
8496 8495 la_els_logi_t *params;
8497 8496 la_els_logi32_t *params32;
8498 8497 fc_remote_node_t *node;
8499 8498 fc_remote_port_t *pd;
8500 8499
8501 8500 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8502 8501 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8503 8502 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8504 8503 rval = EINVAL;
8505 8504 break;
8506 8505 }
8507 8506
8508 8507 if (use32 == B_TRUE) {
8509 8508 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8510 8509 rval = EINVAL;
8511 8510 break;
8512 8511 }
8513 8512 } else {
8514 8513 if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8515 8514 rval = EINVAL;
8516 8515 break;
8517 8516 }
8518 8517 }
8519 8518
8520 8519 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8521 8520 rval = EFAULT;
8522 8521 break;
8523 8522 }
8524 8523
8525 8524 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8526 8525 if (pd == NULL) {
8527 8526 mutex_enter(&port->fp_mutex);
8528 8527 my_pwwn = &port->fp_service_params.nport_ww_name;
8529 8528 mutex_exit(&port->fp_mutex);
8530 8529
8531 8530 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8532 8531 rval = ENXIO;
8533 8532 break;
8534 8533 }
8535 8534
8536 8535 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8537 8536 mutex_enter(&port->fp_mutex);
8538 8537 *params = port->fp_service_params;
8539 8538 mutex_exit(&port->fp_mutex);
8540 8539 } else {
8541 8540 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8542 8541
8543 8542 mutex_enter(&pd->pd_mutex);
8544 8543 params->ls_code.mbz = params->ls_code.ls_code = 0;
8545 8544 params->common_service = pd->pd_csp;
8546 8545 params->nport_ww_name = pd->pd_port_name;
8547 8546 params->class_1 = pd->pd_clsp1;
8548 8547 params->class_2 = pd->pd_clsp2;
8549 8548 params->class_3 = pd->pd_clsp3;
8550 8549 node = pd->pd_remote_nodep;
8551 8550 mutex_exit(&pd->pd_mutex);
8552 8551
8553 8552 bzero(params->reserved, sizeof (params->reserved));
8554 8553
8555 8554 mutex_enter(&node->fd_mutex);
8556 8555 bcopy(node->fd_vv, params->vendor_version,
8557 8556 sizeof (node->fd_vv));
8558 8557 params->node_ww_name = node->fd_node_name;
8559 8558 mutex_exit(&node->fd_mutex);
8560 8559
8561 8560 fctl_release_remote_port(pd);
8562 8561 }
8563 8562
8564 8563 if (use32 == B_TRUE) {
8565 8564 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8566 8565
8567 8566 params32->ls_code.mbz = params->ls_code.mbz;
8568 8567 params32->common_service = params->common_service;
8569 8568 params32->nport_ww_name = params->nport_ww_name;
8570 8569 params32->class_1 = params->class_1;
8571 8570 params32->class_2 = params->class_2;
8572 8571 params32->class_3 = params->class_3;
8573 8572 bzero(params32->reserved, sizeof (params32->reserved));
8574 8573 bcopy(params->vendor_version, params32->vendor_version,
8575 8574 sizeof (node->fd_vv));
8576 8575 params32->node_ww_name = params->node_ww_name;
8577 8576
8578 8577 if (ddi_copyout((void *)params32,
8579 8578 (void *)fcio->fcio_obuf,
8580 8579 sizeof (*params32), mode)) {
8581 8580 rval = EFAULT;
8582 8581 }
8583 8582
8584 8583 kmem_free(params32, sizeof (*params32));
8585 8584 } else {
8586 8585 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8587 8586 sizeof (*params), mode)) {
8588 8587 rval = EFAULT;
8589 8588 }
8590 8589 }
8591 8590
8592 8591 kmem_free(params, sizeof (*params));
8593 8592 if (fp_fcio_copyout(fcio, data, mode)) {
8594 8593 rval = EFAULT;
8595 8594 }
8596 8595 break;
8597 8596 }
8598 8597
8599 8598 case FCIO_DEV_LOGOUT:
8600 8599 case FCIO_DEV_LOGIN:
8601 8600 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8602 8601 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8603 8602 rval = EINVAL;
8604 8603
8605 8604 if (fp_fcio_copyout(fcio, data, mode)) {
8606 8605 rval = EFAULT;
8607 8606 }
8608 8607 break;
8609 8608 }
8610 8609
8611 8610 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8612 8611 jcode = JOB_FCIO_LOGIN;
8613 8612 } else {
8614 8613 jcode = JOB_FCIO_LOGOUT;
8615 8614 }
8616 8615
8617 8616 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8618 8617 bcopy(fcio, kfcio, sizeof (*fcio));
8619 8618
8620 8619 if (kfcio->fcio_ilen) {
8621 8620 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8622 8621 KM_SLEEP);
8623 8622
8624 8623 if (ddi_copyin((void *)fcio->fcio_ibuf,
8625 8624 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8626 8625 mode)) {
8627 8626 rval = EFAULT;
8628 8627
8629 8628 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8630 8629 kmem_free(kfcio, sizeof (*kfcio));
8631 8630 fcio->fcio_errno = job->job_result;
8632 8631 if (fp_fcio_copyout(fcio, data, mode)) {
8633 8632 rval = EFAULT;
8634 8633 }
8635 8634 break;
8636 8635 }
8637 8636 }
8638 8637
8639 8638 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8640 8639 job->job_private = kfcio;
8641 8640
8642 8641 fctl_enque_job(port, job);
8643 8642 fctl_jobwait(job);
8644 8643
8645 8644 rval = job->job_result;
8646 8645
8647 8646 fcio->fcio_errno = kfcio->fcio_errno;
8648 8647 if (fp_fcio_copyout(fcio, data, mode)) {
8649 8648 rval = EFAULT;
8650 8649 }
8651 8650
8652 8651 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8653 8652 kmem_free(kfcio, sizeof (*kfcio));
8654 8653 fctl_dealloc_job(job);
8655 8654 break;
8656 8655
8657 8656 case FCIO_GET_STATE: {
8658 8657 la_wwn_t pwwn;
8659 8658 uint32_t state;
8660 8659 fc_remote_port_t *pd;
8661 8660 fctl_ns_req_t *ns_cmd;
8662 8661
8663 8662 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8664 8663 fcio->fcio_olen != sizeof (state) ||
8665 8664 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8666 8665 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8667 8666 rval = EINVAL;
8668 8667 break;
8669 8668 }
8670 8669
8671 8670 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8672 8671 rval = EFAULT;
8673 8672 break;
8674 8673 }
8675 8674 fcio->fcio_errno = 0;
8676 8675
8677 8676 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8678 8677 if (pd == NULL) {
8679 8678 mutex_enter(&port->fp_mutex);
8680 8679 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8681 8680 mutex_exit(&port->fp_mutex);
8682 8681 job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8683 8682 NULL, NULL, KM_SLEEP);
8684 8683
8685 8684 job->job_counter = 1;
8686 8685 job->job_result = FC_SUCCESS;
8687 8686
8688 8687 ns_cmd = fctl_alloc_ns_cmd(
8689 8688 sizeof (ns_req_gid_pn_t),
8690 8689 sizeof (ns_resp_gid_pn_t),
8691 8690 sizeof (ns_resp_gid_pn_t),
8692 8691 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8693 8692 ASSERT(ns_cmd != NULL);
8694 8693
8695 8694 ns_cmd->ns_cmd_code = NS_GID_PN;
8696 8695 ((ns_req_gid_pn_t *)
8697 8696 (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8698 8697
8699 8698 ret = fp_ns_query(port, ns_cmd, job,
8700 8699 1, KM_SLEEP);
8701 8700
8702 8701 if (ret != FC_SUCCESS || job->job_result !=
8703 8702 FC_SUCCESS) {
8704 8703 if (ret != FC_SUCCESS) {
8705 8704 fcio->fcio_errno = ret;
8706 8705 } else {
8707 8706 fcio->fcio_errno =
8708 8707 job->job_result;
8709 8708 }
8710 8709 rval = EIO;
8711 8710 } else {
8712 8711 state = PORT_DEVICE_INVALID;
8713 8712 }
8714 8713 fctl_free_ns_cmd(ns_cmd);
8715 8714 fctl_dealloc_job(job);
8716 8715 } else {
8717 8716 mutex_exit(&port->fp_mutex);
8718 8717 fcio->fcio_errno = FC_BADWWN;
8719 8718 rval = ENXIO;
8720 8719 }
8721 8720 } else {
8722 8721 mutex_enter(&pd->pd_mutex);
8723 8722 state = pd->pd_state;
8724 8723 mutex_exit(&pd->pd_mutex);
8725 8724
8726 8725 fctl_release_remote_port(pd);
8727 8726 }
8728 8727
8729 8728 if (!rval) {
8730 8729 if (ddi_copyout((void *)&state,
8731 8730 (void *)fcio->fcio_obuf, sizeof (state),
8732 8731 mode)) {
8733 8732 rval = EFAULT;
8734 8733 }
8735 8734 }
8736 8735 if (fp_fcio_copyout(fcio, data, mode)) {
8737 8736 rval = EFAULT;
8738 8737 }
8739 8738 break;
8740 8739 }
8741 8740
8742 8741 case FCIO_DEV_REMOVE: {
8743 8742 la_wwn_t pwwn;
8744 8743 fc_portmap_t *changelist;
8745 8744 fc_remote_port_t *pd;
8746 8745
8747 8746 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8748 8747 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8749 8748 rval = EINVAL;
8750 8749 break;
8751 8750 }
8752 8751
8753 8752 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8754 8753 rval = EFAULT;
8755 8754 break;
8756 8755 }
8757 8756
8758 8757 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8759 8758 if (pd == NULL) {
8760 8759 rval = ENXIO;
8761 8760 fcio->fcio_errno = FC_BADWWN;
8762 8761 if (fp_fcio_copyout(fcio, data, mode)) {
8763 8762 rval = EFAULT;
8764 8763 }
8765 8764 break;
8766 8765 }
8767 8766
8768 8767 mutex_enter(&pd->pd_mutex);
8769 8768 if (pd->pd_ref_count > 1) {
8770 8769 mutex_exit(&pd->pd_mutex);
8771 8770
8772 8771 rval = EBUSY;
8773 8772 fcio->fcio_errno = FC_FAILURE;
8774 8773 fctl_release_remote_port(pd);
8775 8774
8776 8775 if (fp_fcio_copyout(fcio, data, mode)) {
8777 8776 rval = EFAULT;
8778 8777 }
8779 8778 break;
8780 8779 }
8781 8780 mutex_exit(&pd->pd_mutex);
8782 8781
8783 8782 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8784 8783
8785 8784 fctl_copy_portmap(changelist, pd);
8786 8785 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8787 8786 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8788 8787
8789 8788 fctl_release_remote_port(pd);
8790 8789 break;
8791 8790 }
8792 8791
8793 8792 case FCIO_GET_FCODE_REV: {
8794 8793 caddr_t fcode_rev;
8795 8794 fc_fca_pm_t pm;
8796 8795
8797 8796 if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8798 8797 fcio->fcio_xfer != FCIO_XFER_READ) {
8799 8798 rval = EINVAL;
8800 8799 break;
8801 8800 }
8802 8801 bzero((caddr_t)&pm, sizeof (pm));
8803 8802
8804 8803 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8805 8804
8806 8805 pm.pm_cmd_flags = FC_FCA_PM_READ;
8807 8806 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8808 8807 pm.pm_data_len = fcio->fcio_olen;
8809 8808 pm.pm_data_buf = fcode_rev;
8810 8809
8811 8810 ret = port->fp_fca_tran->fca_port_manage(
8812 8811 port->fp_fca_handle, &pm);
8813 8812
8814 8813 if (ret == FC_SUCCESS) {
8815 8814 if (ddi_copyout((void *)fcode_rev,
8816 8815 (void *)fcio->fcio_obuf,
8817 8816 fcio->fcio_olen, mode) == 0) {
8818 8817 if (fp_fcio_copyout(fcio, data, mode)) {
8819 8818 rval = EFAULT;
8820 8819 }
8821 8820 } else {
8822 8821 rval = EFAULT;
8823 8822 }
8824 8823 } else {
8825 8824 /*
8826 8825 * check if buffer was not large enough to obtain
8827 8826 * FCODE version.
8828 8827 */
8829 8828 if (pm.pm_data_len > fcio->fcio_olen) {
8830 8829 rval = ENOMEM;
8831 8830 } else {
8832 8831 rval = EIO;
8833 8832 }
8834 8833 fcio->fcio_errno = ret;
8835 8834 if (fp_fcio_copyout(fcio, data, mode)) {
8836 8835 rval = EFAULT;
8837 8836 }
8838 8837 }
8839 8838 kmem_free(fcode_rev, fcio->fcio_olen);
8840 8839 break;
8841 8840 }
8842 8841
8843 8842 case FCIO_GET_FW_REV: {
8844 8843 caddr_t fw_rev;
8845 8844 fc_fca_pm_t pm;
8846 8845
8847 8846 if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8848 8847 fcio->fcio_xfer != FCIO_XFER_READ) {
8849 8848 rval = EINVAL;
8850 8849 break;
8851 8850 }
8852 8851 bzero((caddr_t)&pm, sizeof (pm));
8853 8852
8854 8853 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8855 8854
8856 8855 pm.pm_cmd_flags = FC_FCA_PM_READ;
8857 8856 pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8858 8857 pm.pm_data_len = fcio->fcio_olen;
8859 8858 pm.pm_data_buf = fw_rev;
8860 8859
8861 8860 ret = port->fp_fca_tran->fca_port_manage(
8862 8861 port->fp_fca_handle, &pm);
8863 8862
8864 8863 if (ret == FC_SUCCESS) {
8865 8864 if (ddi_copyout((void *)fw_rev,
8866 8865 (void *)fcio->fcio_obuf,
8867 8866 fcio->fcio_olen, mode) == 0) {
8868 8867 if (fp_fcio_copyout(fcio, data, mode)) {
8869 8868 rval = EFAULT;
8870 8869 }
8871 8870 } else {
8872 8871 rval = EFAULT;
8873 8872 }
8874 8873 } else {
8875 8874 if (fp_fcio_copyout(fcio, data, mode)) {
8876 8875 rval = EFAULT;
8877 8876 }
8878 8877 rval = EIO;
8879 8878 }
8880 8879 kmem_free(fw_rev, fcio->fcio_olen);
8881 8880 break;
8882 8881 }
8883 8882
8884 8883 case FCIO_GET_DUMP_SIZE: {
8885 8884 uint32_t dump_size;
8886 8885 fc_fca_pm_t pm;
8887 8886
8888 8887 if (fcio->fcio_olen != sizeof (dump_size) ||
8889 8888 fcio->fcio_xfer != FCIO_XFER_READ) {
8890 8889 rval = EINVAL;
8891 8890 break;
8892 8891 }
8893 8892 bzero((caddr_t)&pm, sizeof (pm));
8894 8893 pm.pm_cmd_flags = FC_FCA_PM_READ;
8895 8894 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8896 8895 pm.pm_data_len = sizeof (dump_size);
8897 8896 pm.pm_data_buf = (caddr_t)&dump_size;
8898 8897
8899 8898 ret = port->fp_fca_tran->fca_port_manage(
8900 8899 port->fp_fca_handle, &pm);
8901 8900
8902 8901 if (ret == FC_SUCCESS) {
8903 8902 if (ddi_copyout((void *)&dump_size,
8904 8903 (void *)fcio->fcio_obuf, sizeof (dump_size),
8905 8904 mode) == 0) {
8906 8905 if (fp_fcio_copyout(fcio, data, mode)) {
8907 8906 rval = EFAULT;
8908 8907 }
8909 8908 } else {
8910 8909 rval = EFAULT;
8911 8910 }
8912 8911 } else {
8913 8912 fcio->fcio_errno = ret;
8914 8913 rval = EIO;
8915 8914 if (fp_fcio_copyout(fcio, data, mode)) {
8916 8915 rval = EFAULT;
8917 8916 }
8918 8917 }
8919 8918 break;
8920 8919 }
8921 8920
8922 8921 case FCIO_DOWNLOAD_FW: {
8923 8922 caddr_t firmware;
8924 8923 fc_fca_pm_t pm;
8925 8924
8926 8925 if (fcio->fcio_ilen <= 0 ||
8927 8926 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8928 8927 rval = EINVAL;
8929 8928 break;
8930 8929 }
8931 8930
8932 8931 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8933 8932 if (ddi_copyin(fcio->fcio_ibuf, firmware,
8934 8933 fcio->fcio_ilen, mode)) {
8935 8934 rval = EFAULT;
8936 8935 kmem_free(firmware, fcio->fcio_ilen);
8937 8936 break;
8938 8937 }
8939 8938
8940 8939 bzero((caddr_t)&pm, sizeof (pm));
8941 8940 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8942 8941 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8943 8942 pm.pm_data_len = fcio->fcio_ilen;
8944 8943 pm.pm_data_buf = firmware;
8945 8944
8946 8945 ret = port->fp_fca_tran->fca_port_manage(
8947 8946 port->fp_fca_handle, &pm);
8948 8947
8949 8948 kmem_free(firmware, fcio->fcio_ilen);
8950 8949
8951 8950 if (ret != FC_SUCCESS) {
8952 8951 fcio->fcio_errno = ret;
8953 8952 rval = EIO;
8954 8953 if (fp_fcio_copyout(fcio, data, mode)) {
8955 8954 rval = EFAULT;
8956 8955 }
8957 8956 }
8958 8957 break;
8959 8958 }
8960 8959
8961 8960 case FCIO_DOWNLOAD_FCODE: {
8962 8961 caddr_t fcode;
8963 8962 fc_fca_pm_t pm;
8964 8963
8965 8964 if (fcio->fcio_ilen <= 0 ||
8966 8965 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8967 8966 rval = EINVAL;
8968 8967 break;
8969 8968 }
8970 8969
8971 8970 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8972 8971 if (ddi_copyin(fcio->fcio_ibuf, fcode,
8973 8972 fcio->fcio_ilen, mode)) {
8974 8973 rval = EFAULT;
8975 8974 kmem_free(fcode, fcio->fcio_ilen);
8976 8975 break;
8977 8976 }
8978 8977
8979 8978 bzero((caddr_t)&pm, sizeof (pm));
8980 8979 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8981 8980 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8982 8981 pm.pm_data_len = fcio->fcio_ilen;
8983 8982 pm.pm_data_buf = fcode;
8984 8983
8985 8984 ret = port->fp_fca_tran->fca_port_manage(
8986 8985 port->fp_fca_handle, &pm);
8987 8986
8988 8987 kmem_free(fcode, fcio->fcio_ilen);
8989 8988
8990 8989 if (ret != FC_SUCCESS) {
8991 8990 fcio->fcio_errno = ret;
8992 8991 rval = EIO;
8993 8992 if (fp_fcio_copyout(fcio, data, mode)) {
8994 8993 rval = EFAULT;
8995 8994 }
8996 8995 }
8997 8996 break;
8998 8997 }
8999 8998
9000 8999 case FCIO_FORCE_DUMP:
9001 9000 ret = port->fp_fca_tran->fca_reset(
9002 9001 port->fp_fca_handle, FC_FCA_CORE);
9003 9002
9004 9003 if (ret != FC_SUCCESS) {
9005 9004 fcio->fcio_errno = ret;
9006 9005 rval = EIO;
9007 9006 if (fp_fcio_copyout(fcio, data, mode)) {
9008 9007 rval = EFAULT;
9009 9008 }
9010 9009 }
9011 9010 break;
9012 9011
9013 9012 case FCIO_GET_DUMP: {
9014 9013 caddr_t dump;
9015 9014 uint32_t dump_size;
9016 9015 fc_fca_pm_t pm;
9017 9016
9018 9017 if (fcio->fcio_xfer != FCIO_XFER_READ) {
9019 9018 rval = EINVAL;
9020 9019 break;
9021 9020 }
9022 9021 bzero((caddr_t)&pm, sizeof (pm));
9023 9022
9024 9023 pm.pm_cmd_flags = FC_FCA_PM_READ;
9025 9024 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
9026 9025 pm.pm_data_len = sizeof (dump_size);
9027 9026 pm.pm_data_buf = (caddr_t)&dump_size;
9028 9027
9029 9028 ret = port->fp_fca_tran->fca_port_manage(
9030 9029 port->fp_fca_handle, &pm);
9031 9030
9032 9031 if (ret != FC_SUCCESS) {
9033 9032 fcio->fcio_errno = ret;
9034 9033 rval = EIO;
9035 9034 if (fp_fcio_copyout(fcio, data, mode)) {
9036 9035 rval = EFAULT;
9037 9036 }
9038 9037 break;
9039 9038 }
9040 9039 if (fcio->fcio_olen != dump_size) {
9041 9040 fcio->fcio_errno = FC_NOMEM;
9042 9041 rval = EINVAL;
9043 9042 if (fp_fcio_copyout(fcio, data, mode)) {
9044 9043 rval = EFAULT;
9045 9044 }
9046 9045 break;
9047 9046 }
9048 9047
9049 9048 dump = kmem_zalloc(dump_size, KM_SLEEP);
9050 9049
9051 9050 bzero((caddr_t)&pm, sizeof (pm));
9052 9051 pm.pm_cmd_flags = FC_FCA_PM_READ;
9053 9052 pm.pm_cmd_code = FC_PORT_GET_DUMP;
9054 9053 pm.pm_data_len = dump_size;
9055 9054 pm.pm_data_buf = dump;
9056 9055
9057 9056 ret = port->fp_fca_tran->fca_port_manage(
9058 9057 port->fp_fca_handle, &pm);
9059 9058
9060 9059 if (ret == FC_SUCCESS) {
9061 9060 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
9062 9061 dump_size, mode) == 0) {
9063 9062 if (fp_fcio_copyout(fcio, data, mode)) {
9064 9063 rval = EFAULT;
9065 9064 }
9066 9065 } else {
9067 9066 rval = EFAULT;
9068 9067 }
9069 9068 } else {
9070 9069 fcio->fcio_errno = ret;
9071 9070 rval = EIO;
9072 9071 if (fp_fcio_copyout(fcio, data, mode)) {
9073 9072 rval = EFAULT;
9074 9073 }
9075 9074 }
9076 9075 kmem_free(dump, dump_size);
9077 9076 break;
9078 9077 }
9079 9078
9080 9079 case FCIO_GET_TOPOLOGY: {
9081 9080 uint32_t user_topology;
9082 9081
9083 9082 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9084 9083 fcio->fcio_olen != sizeof (user_topology)) {
9085 9084 rval = EINVAL;
9086 9085 break;
9087 9086 }
9088 9087
9089 9088 mutex_enter(&port->fp_mutex);
9090 9089 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9091 9090 user_topology = FC_TOP_UNKNOWN;
9092 9091 } else {
9093 9092 user_topology = port->fp_topology;
9094 9093 }
9095 9094 mutex_exit(&port->fp_mutex);
9096 9095
9097 9096 if (ddi_copyout((void *)&user_topology,
9098 9097 (void *)fcio->fcio_obuf, sizeof (user_topology),
9099 9098 mode)) {
9100 9099 rval = EFAULT;
9101 9100 }
9102 9101 break;
9103 9102 }
9104 9103
9105 9104 case FCIO_RESET_LINK: {
9106 9105 la_wwn_t pwwn;
9107 9106
9108 9107 /*
9109 9108 * Look at the output buffer field; if this field has zero
9110 9109 * bytes then attempt to reset the local link/loop. If the
9111 9110 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9112 9111 * and if yes, determine the LFA and reset the remote LIP
9113 9112 * by LINIT ELS.
9114 9113 */
9115 9114
9116 9115 if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9117 9116 fcio->fcio_ilen != sizeof (pwwn)) {
9118 9117 rval = EINVAL;
9119 9118 break;
9120 9119 }
9121 9120
9122 9121 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9123 9122 sizeof (pwwn), mode)) {
9124 9123 rval = EFAULT;
9125 9124 break;
9126 9125 }
9127 9126
9128 9127 mutex_enter(&port->fp_mutex);
9129 9128 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9130 9129 mutex_exit(&port->fp_mutex);
9131 9130 break;
9132 9131 }
9133 9132 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9134 9133 mutex_exit(&port->fp_mutex);
9135 9134
9136 9135 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9137 9136 if (job == NULL) {
9138 9137 rval = ENOMEM;
9139 9138 break;
9140 9139 }
9141 9140 job->job_counter = 1;
9142 9141 job->job_private = (void *)&pwwn;
9143 9142
9144 9143 fctl_enque_job(port, job);
9145 9144 fctl_jobwait(job);
9146 9145
9147 9146 mutex_enter(&port->fp_mutex);
9148 9147 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9149 9148 mutex_exit(&port->fp_mutex);
9150 9149
9151 9150 if (job->job_result != FC_SUCCESS) {
9152 9151 fcio->fcio_errno = job->job_result;
9153 9152 rval = EIO;
9154 9153 if (fp_fcio_copyout(fcio, data, mode)) {
9155 9154 rval = EFAULT;
9156 9155 }
9157 9156 }
9158 9157 fctl_dealloc_job(job);
9159 9158 break;
9160 9159 }
9161 9160
9162 9161 case FCIO_RESET_HARD:
9163 9162 ret = port->fp_fca_tran->fca_reset(
9164 9163 port->fp_fca_handle, FC_FCA_RESET);
9165 9164 if (ret != FC_SUCCESS) {
9166 9165 fcio->fcio_errno = ret;
9167 9166 rval = EIO;
9168 9167 if (fp_fcio_copyout(fcio, data, mode)) {
9169 9168 rval = EFAULT;
9170 9169 }
9171 9170 }
9172 9171 break;
9173 9172
9174 9173 case FCIO_RESET_HARD_CORE:
9175 9174 ret = port->fp_fca_tran->fca_reset(
9176 9175 port->fp_fca_handle, FC_FCA_RESET_CORE);
9177 9176 if (ret != FC_SUCCESS) {
9178 9177 rval = EIO;
9179 9178 fcio->fcio_errno = ret;
9180 9179 if (fp_fcio_copyout(fcio, data, mode)) {
9181 9180 rval = EFAULT;
9182 9181 }
9183 9182 }
9184 9183 break;
9185 9184
9186 9185 case FCIO_DIAG: {
9187 9186 fc_fca_pm_t pm;
9188 9187
9189 9188 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9190 9189
9191 9190 /* Validate user buffer from ioctl call. */
9192 9191 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9193 9192 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9194 9193 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9195 9194 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9196 9195 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9197 9196 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9198 9197 rval = EFAULT;
9199 9198 break;
9200 9199 }
9201 9200
9202 9201 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9203 9202 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9204 9203 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9205 9204 fcio->fcio_ilen, mode)) {
9206 9205 rval = EFAULT;
9207 9206 goto fp_fcio_diag_cleanup;
9208 9207 }
9209 9208 }
9210 9209
9211 9210 if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9212 9211 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9213 9212 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9214 9213 fcio->fcio_alen, mode)) {
9215 9214 rval = EFAULT;
9216 9215 goto fp_fcio_diag_cleanup;
9217 9216 }
9218 9217 }
9219 9218
9220 9219 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9221 9220 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9222 9221 }
9223 9222
9224 9223 pm.pm_cmd_code = FC_PORT_DIAG;
9225 9224 pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9226 9225
9227 9226 ret = port->fp_fca_tran->fca_port_manage(
9228 9227 port->fp_fca_handle, &pm);
9229 9228
9230 9229 if (ret != FC_SUCCESS) {
9231 9230 if (ret == FC_INVALID_REQUEST) {
9232 9231 rval = ENOTTY;
9233 9232 } else {
9234 9233 rval = EIO;
9235 9234 }
9236 9235
9237 9236 fcio->fcio_errno = ret;
9238 9237 if (fp_fcio_copyout(fcio, data, mode)) {
9239 9238 rval = EFAULT;
9240 9239 }
9241 9240 goto fp_fcio_diag_cleanup;
9242 9241 }
9243 9242
9244 9243 /*
9245 9244 * pm_stat_len will contain the number of status bytes
9246 9245 * an FCA driver requires to return the complete status
9247 9246 * of the requested diag operation. If the user buffer
9248 9247 * is not large enough to hold the entire status, We
9249 9248 * copy only the portion of data the fits in the buffer and
9250 9249 * return a ENOMEM to the user application.
9251 9250 */
9252 9251 if (pm.pm_stat_len > fcio->fcio_olen) {
9253 9252 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9254 9253 "fp:FCIO_DIAG:status buffer too small\n");
9255 9254
9256 9255 rval = ENOMEM;
9257 9256 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9258 9257 fcio->fcio_olen, mode)) {
9259 9258 rval = EFAULT;
9260 9259 goto fp_fcio_diag_cleanup;
9261 9260 }
9262 9261 } else {
9263 9262 /*
9264 9263 * Copy only data pm_stat_len bytes of data
9265 9264 */
9266 9265 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9267 9266 pm.pm_stat_len, mode)) {
9268 9267 rval = EFAULT;
9269 9268 goto fp_fcio_diag_cleanup;
9270 9269 }
9271 9270 }
9272 9271
9273 9272 if (fp_fcio_copyout(fcio, data, mode)) {
9274 9273 rval = EFAULT;
9275 9274 }
9276 9275
9277 9276 fp_fcio_diag_cleanup:
9278 9277 if (pm.pm_cmd_buf != NULL) {
9279 9278 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9280 9279 }
9281 9280 if (pm.pm_data_buf != NULL) {
9282 9281 kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9283 9282 }
9284 9283 if (pm.pm_stat_buf != NULL) {
9285 9284 kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9286 9285 }
9287 9286
9288 9287 break;
9289 9288 }
9290 9289
9291 9290 case FCIO_GET_NODE_ID: {
9292 9291 /* validate parameters */
9293 9292 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9294 9293 fcio->fcio_olen < sizeof (fc_rnid_t)) {
9295 9294 rval = EINVAL;
9296 9295 break;
9297 9296 }
9298 9297
9299 9298 rval = fp_get_rnid(port, data, mode, fcio);
9300 9299
9301 9300 /* ioctl handling is over */
9302 9301 break;
9303 9302 }
9304 9303
9305 9304 case FCIO_SEND_NODE_ID: {
9306 9305 la_wwn_t pwwn;
9307 9306
9308 9307 /* validate parameters */
9309 9308 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9310 9309 fcio->fcio_xfer != FCIO_XFER_READ) {
9311 9310 rval = EINVAL;
9312 9311 break;
9313 9312 }
9314 9313
9315 9314 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9316 9315 sizeof (la_wwn_t), mode)) {
9317 9316 rval = EFAULT;
9318 9317 break;
9319 9318 }
9320 9319
9321 9320 rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9322 9321
9323 9322 /* ioctl handling is over */
9324 9323 break;
9325 9324 }
9326 9325
9327 9326 case FCIO_SET_NODE_ID: {
9328 9327 if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9329 9328 (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9330 9329 rval = EINVAL;
9331 9330 break;
9332 9331 }
9333 9332
9334 9333 rval = fp_set_rnid(port, data, mode, fcio);
9335 9334 break;
9336 9335 }
9337 9336
9338 9337 case FCIO_LINK_STATUS: {
9339 9338 fc_portid_t rls_req;
9340 9339 fc_rls_acc_t *rls_acc;
9341 9340 fc_fca_pm_t pm;
9342 9341 uint32_t dest, src_id;
9343 9342 fp_cmd_t *cmd;
9344 9343 fc_remote_port_t *pd;
9345 9344 uchar_t pd_flags;
9346 9345
9347 9346 /* validate parameters */
9348 9347 if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9349 9348 fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9350 9349 fcio->fcio_xfer != FCIO_XFER_RW) {
9351 9350 rval = EINVAL;
9352 9351 break;
9353 9352 }
9354 9353
9355 9354 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9356 9355 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9357 9356 rval = EINVAL;
9358 9357 break;
9359 9358 }
9360 9359
9361 9360 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9362 9361 sizeof (fc_portid_t), mode)) {
9363 9362 rval = EFAULT;
9364 9363 break;
9365 9364 }
9366 9365
9367 9366
9368 9367 /* Determine the destination of the RLS frame */
9369 9368 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9370 9369 dest = FS_FABRIC_F_PORT;
9371 9370 } else {
9372 9371 dest = rls_req.port_id;
9373 9372 }
9374 9373
9375 9374 mutex_enter(&port->fp_mutex);
9376 9375 src_id = port->fp_port_id.port_id;
9377 9376 mutex_exit(&port->fp_mutex);
9378 9377
9379 9378 /* If dest is zero OR same as FCA ID, then use port_manage() */
9380 9379 if (dest == 0 || dest == src_id) {
9381 9380
9382 9381 /* Allocate memory for link error status block */
9383 9382 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9384 9383 ASSERT(rls_acc != NULL);
9385 9384
9386 9385 /* Prepare the port management structure */
9387 9386 bzero((caddr_t)&pm, sizeof (pm));
9388 9387
9389 9388 pm.pm_cmd_flags = FC_FCA_PM_READ;
9390 9389 pm.pm_cmd_code = FC_PORT_RLS;
9391 9390 pm.pm_data_len = sizeof (*rls_acc);
9392 9391 pm.pm_data_buf = (caddr_t)rls_acc;
9393 9392
9394 9393 /* Get the adapter's link error status block */
9395 9394 ret = port->fp_fca_tran->fca_port_manage(
9396 9395 port->fp_fca_handle, &pm);
9397 9396
9398 9397 if (ret == FC_SUCCESS) {
9399 9398 /* xfer link status block to userland */
9400 9399 if (ddi_copyout((void *)rls_acc,
9401 9400 (void *)fcio->fcio_obuf,
9402 9401 sizeof (*rls_acc), mode) == 0) {
9403 9402 if (fp_fcio_copyout(fcio, data,
9404 9403 mode)) {
9405 9404 rval = EFAULT;
9406 9405 }
9407 9406 } else {
9408 9407 rval = EFAULT;
9409 9408 }
9410 9409 } else {
9411 9410 rval = EIO;
9412 9411 fcio->fcio_errno = ret;
9413 9412 if (fp_fcio_copyout(fcio, data, mode)) {
9414 9413 rval = EFAULT;
9415 9414 }
9416 9415 }
9417 9416
9418 9417 kmem_free(rls_acc, sizeof (*rls_acc));
9419 9418
9420 9419 /* ioctl handling is over */
9421 9420 break;
9422 9421 }
9423 9422
9424 9423 /*
9425 9424 * Send RLS to the destination port.
9426 9425 * Having RLS frame destination is as FPORT is not yet
9427 9426 * supported and will be implemented in future, if needed.
9428 9427 * Following call to get "pd" will fail if dest is FPORT
9429 9428 */
9430 9429 pd = fctl_hold_remote_port_by_did(port, dest);
9431 9430 if (pd == NULL) {
9432 9431 fcio->fcio_errno = FC_BADOBJECT;
9433 9432 rval = ENXIO;
9434 9433 if (fp_fcio_copyout(fcio, data, mode)) {
9435 9434 rval = EFAULT;
9436 9435 }
9437 9436 break;
9438 9437 }
9439 9438
9440 9439 mutex_enter(&pd->pd_mutex);
9441 9440 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9442 9441 mutex_exit(&pd->pd_mutex);
9443 9442 fctl_release_remote_port(pd);
9444 9443
9445 9444 fcio->fcio_errno = FC_LOGINREQ;
9446 9445 rval = EINVAL;
9447 9446 if (fp_fcio_copyout(fcio, data, mode)) {
9448 9447 rval = EFAULT;
9449 9448 }
9450 9449 break;
9451 9450 }
9452 9451 ASSERT(pd->pd_login_count >= 1);
9453 9452 mutex_exit(&pd->pd_mutex);
9454 9453
9455 9454 /*
9456 9455 * Allocate job structure and set job_code as DUMMY,
9457 9456 * because we will not go through the job thread.
9458 9457 * Instead fp_sendcmd() is called directly here.
9459 9458 */
9460 9459 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9461 9460 NULL, NULL, KM_SLEEP);
9462 9461 ASSERT(job != NULL);
9463 9462
9464 9463 job->job_counter = 1;
9465 9464
9466 9465 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9467 9466 sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9468 9467 if (cmd == NULL) {
9469 9468 fcio->fcio_errno = FC_NOMEM;
9470 9469 rval = ENOMEM;
9471 9470
9472 9471 fctl_release_remote_port(pd);
9473 9472
9474 9473 fctl_dealloc_job(job);
9475 9474 if (fp_fcio_copyout(fcio, data, mode)) {
9476 9475 rval = EFAULT;
9477 9476 }
9478 9477 break;
9479 9478 }
9480 9479
9481 9480 /* Allocate memory for link error status block */
9482 9481 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9483 9482
9484 9483 mutex_enter(&port->fp_mutex);
9485 9484 mutex_enter(&pd->pd_mutex);
9486 9485
9487 9486 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9488 9487 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9489 9488 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9490 9489 cmd->cmd_retry_count = 1;
9491 9490 cmd->cmd_ulp_pkt = NULL;
9492 9491
9493 9492 fp_rls_init(cmd, job);
9494 9493
9495 9494 job->job_private = (void *)rls_acc;
9496 9495
9497 9496 pd_flags = pd->pd_flags;
9498 9497 pd->pd_flags = PD_ELS_IN_PROGRESS;
9499 9498
9500 9499 mutex_exit(&pd->pd_mutex);
9501 9500 mutex_exit(&port->fp_mutex);
9502 9501
9503 9502 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9504 9503 fctl_jobwait(job);
9505 9504
9506 9505 fcio->fcio_errno = job->job_result;
9507 9506 if (job->job_result == FC_SUCCESS) {
9508 9507 ASSERT(pd != NULL);
9509 9508 /*
9510 9509 * link error status block is now available.
9511 9510 * Copy it to userland
9512 9511 */
9513 9512 ASSERT(job->job_private == (void *)rls_acc);
9514 9513 if (ddi_copyout((void *)rls_acc,
9515 9514 (void *)fcio->fcio_obuf,
9516 9515 sizeof (*rls_acc), mode) == 0) {
9517 9516 if (fp_fcio_copyout(fcio, data,
9518 9517 mode)) {
9519 9518 rval = EFAULT;
9520 9519 }
9521 9520 } else {
9522 9521 rval = EFAULT;
9523 9522 }
9524 9523 } else {
9525 9524 rval = EIO;
9526 9525 }
9527 9526 } else {
9528 9527 rval = EIO;
9529 9528 fp_free_pkt(cmd);
9530 9529 }
9531 9530
9532 9531 if (rval) {
9533 9532 mutex_enter(&port->fp_mutex);
9534 9533 mutex_enter(&pd->pd_mutex);
9535 9534 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9536 9535 pd->pd_flags = pd_flags;
9537 9536 }
9538 9537 mutex_exit(&pd->pd_mutex);
9539 9538 mutex_exit(&port->fp_mutex);
9540 9539 }
9541 9540
9542 9541 fctl_release_remote_port(pd);
9543 9542 fctl_dealloc_job(job);
9544 9543 kmem_free(rls_acc, sizeof (*rls_acc));
9545 9544
9546 9545 if (fp_fcio_copyout(fcio, data, mode)) {
9547 9546 rval = EFAULT;
9548 9547 }
9549 9548 break;
9550 9549 }
9551 9550
9552 9551 case FCIO_NS: {
9553 9552 fc_ns_cmd_t *ns_req;
9554 9553 fc_ns_cmd32_t *ns_req32;
9555 9554 fctl_ns_req_t *ns_cmd;
9556 9555
9557 9556 if (use32 == B_TRUE) {
9558 9557 if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9559 9558 rval = EINVAL;
9560 9559 break;
9561 9560 }
9562 9561
9563 9562 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9564 9563 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9565 9564
9566 9565 if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9567 9566 sizeof (*ns_req32), mode)) {
9568 9567 rval = EFAULT;
9569 9568 kmem_free(ns_req, sizeof (*ns_req));
9570 9569 kmem_free(ns_req32, sizeof (*ns_req32));
9571 9570 break;
9572 9571 }
9573 9572
9574 9573 ns_req->ns_flags = ns_req32->ns_flags;
9575 9574 ns_req->ns_cmd = ns_req32->ns_cmd;
9576 9575 ns_req->ns_req_len = ns_req32->ns_req_len;
9577 9576 ns_req->ns_req_payload = ns_req32->ns_req_payload;
9578 9577 ns_req->ns_resp_len = ns_req32->ns_resp_len;
9579 9578 ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9580 9579 ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9581 9580 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9582 9581
9583 9582 kmem_free(ns_req32, sizeof (*ns_req32));
9584 9583 } else {
9585 9584 if (fcio->fcio_ilen != sizeof (*ns_req)) {
9586 9585 rval = EINVAL;
9587 9586 break;
9588 9587 }
9589 9588
9590 9589 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9591 9590
9592 9591 if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9593 9592 sizeof (fc_ns_cmd_t), mode)) {
9594 9593 rval = EFAULT;
9595 9594 kmem_free(ns_req, sizeof (*ns_req));
9596 9595 break;
9597 9596 }
9598 9597 }
9599 9598
9600 9599 if (ns_req->ns_req_len <= 0) {
9601 9600 rval = EINVAL;
9602 9601 kmem_free(ns_req, sizeof (*ns_req));
9603 9602 break;
9604 9603 }
9605 9604
9606 9605 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9607 9606 ASSERT(job != NULL);
9608 9607
9609 9608 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9610 9609 ns_req->ns_resp_len, ns_req->ns_resp_len,
9611 9610 FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9612 9611 ASSERT(ns_cmd != NULL);
9613 9612 ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9614 9613
9615 9614 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9616 9615 ns_cmd->ns_gan_max = 1;
9617 9616 ns_cmd->ns_gan_index = 0;
9618 9617 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9619 9618 }
9620 9619
9621 9620 if (ddi_copyin(ns_req->ns_req_payload,
9622 9621 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9623 9622 rval = EFAULT;
9624 9623 fctl_free_ns_cmd(ns_cmd);
9625 9624 fctl_dealloc_job(job);
9626 9625 kmem_free(ns_req, sizeof (*ns_req));
9627 9626 break;
9628 9627 }
9629 9628
9630 9629 job->job_private = (void *)ns_cmd;
9631 9630 fctl_enque_job(port, job);
9632 9631 fctl_jobwait(job);
9633 9632 rval = job->job_result;
9634 9633
9635 9634 if (rval == FC_SUCCESS) {
9636 9635 if (ns_req->ns_resp_len) {
9637 9636 if (ddi_copyout(ns_cmd->ns_data_buf,
9638 9637 ns_req->ns_resp_payload,
9639 9638 ns_cmd->ns_data_len, mode)) {
9640 9639 rval = EFAULT;
9641 9640 fctl_free_ns_cmd(ns_cmd);
9642 9641 fctl_dealloc_job(job);
9643 9642 kmem_free(ns_req, sizeof (*ns_req));
9644 9643 break;
9645 9644 }
9646 9645 }
9647 9646 } else {
9648 9647 rval = EIO;
9649 9648 }
9650 9649 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9651 9650 fctl_free_ns_cmd(ns_cmd);
9652 9651 fctl_dealloc_job(job);
9653 9652 kmem_free(ns_req, sizeof (*ns_req));
9654 9653
9655 9654 if (fp_fcio_copyout(fcio, data, mode)) {
9656 9655 rval = EFAULT;
9657 9656 }
9658 9657 break;
9659 9658 }
9660 9659
9661 9660 default:
9662 9661 rval = ENOTTY;
9663 9662 break;
9664 9663 }
9665 9664
9666 9665 /*
9667 9666 * If set, reset the EXCL busy bit to
9668 9667 * receive other exclusive access commands
9669 9668 */
9670 9669 mutex_enter(&port->fp_mutex);
9671 9670 if (port->fp_flag & FP_EXCL_BUSY) {
9672 9671 port->fp_flag &= ~FP_EXCL_BUSY;
9673 9672 }
9674 9673 mutex_exit(&port->fp_mutex);
9675 9674
9676 9675 return (rval);
9677 9676 }
9678 9677
9679 9678
9680 9679 /*
9681 9680 * This function assumes that the response length
9682 9681 * is same regardless of data model (LP32 or LP64)
9683 9682 * which is true for all the ioctls currently
9684 9683 * supported.
9685 9684 */
9686 9685 static int
9687 9686 fp_copyout(void *from, void *to, size_t len, int mode)
9688 9687 {
9689 9688 return (ddi_copyout(from, to, len, mode));
9690 9689 }
9691 9690
9692 9691 /*
9693 9692 * This function does the set rnid
9694 9693 */
9695 9694 static int
9696 9695 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9697 9696 {
9698 9697 int rval = 0;
9699 9698 fc_rnid_t *rnid;
9700 9699 fc_fca_pm_t pm;
9701 9700
9702 9701 /* Allocate memory for node id block */
9703 9702 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9704 9703
9705 9704 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9706 9705 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9707 9706 kmem_free(rnid, sizeof (fc_rnid_t));
9708 9707 return (EFAULT);
9709 9708 }
9710 9709
9711 9710 /* Prepare the port management structure */
9712 9711 bzero((caddr_t)&pm, sizeof (pm));
9713 9712
9714 9713 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9715 9714 pm.pm_cmd_code = FC_PORT_SET_NODE_ID;
9716 9715 pm.pm_data_len = sizeof (*rnid);
9717 9716 pm.pm_data_buf = (caddr_t)rnid;
9718 9717
9719 9718 /* Get the adapter's node data */
9720 9719 rval = port->fp_fca_tran->fca_port_manage(
9721 9720 port->fp_fca_handle, &pm);
9722 9721
9723 9722 if (rval != FC_SUCCESS) {
9724 9723 fcio->fcio_errno = rval;
9725 9724 rval = EIO;
9726 9725 if (fp_fcio_copyout(fcio, data, mode)) {
9727 9726 rval = EFAULT;
9728 9727 }
9729 9728 } else {
9730 9729 mutex_enter(&port->fp_mutex);
9731 9730 /* copy to the port structure */
9732 9731 bcopy(rnid, &port->fp_rnid_params,
9733 9732 sizeof (port->fp_rnid_params));
9734 9733 mutex_exit(&port->fp_mutex);
9735 9734 }
9736 9735
9737 9736 kmem_free(rnid, sizeof (fc_rnid_t));
9738 9737
9739 9738 if (rval != FC_SUCCESS) {
9740 9739 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9741 9740 }
9742 9741
9743 9742 return (rval);
9744 9743 }
9745 9744
9746 9745 /*
9747 9746 * This function does the local pwwn get rnid
9748 9747 */
9749 9748 static int
9750 9749 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9751 9750 {
9752 9751 fc_rnid_t *rnid;
9753 9752 fc_fca_pm_t pm;
9754 9753 int rval = 0;
9755 9754 uint32_t ret;
9756 9755
9757 9756 /* Allocate memory for rnid data block */
9758 9757 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9759 9758
9760 9759 mutex_enter(&port->fp_mutex);
9761 9760 if (port->fp_rnid_init == 1) {
9762 9761 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9763 9762 mutex_exit(&port->fp_mutex);
9764 9763 /* xfer node info to userland */
9765 9764 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9766 9765 sizeof (*rnid), mode) == 0) {
9767 9766 if (fp_fcio_copyout(fcio, data, mode)) {
9768 9767 rval = EFAULT;
9769 9768 }
9770 9769 } else {
9771 9770 rval = EFAULT;
9772 9771 }
9773 9772
9774 9773 kmem_free(rnid, sizeof (fc_rnid_t));
9775 9774
9776 9775 if (rval != FC_SUCCESS) {
9777 9776 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9778 9777 rval);
9779 9778 }
9780 9779
9781 9780 return (rval);
9782 9781 }
9783 9782 mutex_exit(&port->fp_mutex);
9784 9783
9785 9784 /* Prepare the port management structure */
9786 9785 bzero((caddr_t)&pm, sizeof (pm));
9787 9786
9788 9787 pm.pm_cmd_flags = FC_FCA_PM_READ;
9789 9788 pm.pm_cmd_code = FC_PORT_GET_NODE_ID;
9790 9789 pm.pm_data_len = sizeof (fc_rnid_t);
9791 9790 pm.pm_data_buf = (caddr_t)rnid;
9792 9791
9793 9792 /* Get the adapter's node data */
9794 9793 ret = port->fp_fca_tran->fca_port_manage(
9795 9794 port->fp_fca_handle,
9796 9795 &pm);
9797 9796
9798 9797 if (ret == FC_SUCCESS) {
9799 9798 /* initialize in the port_info */
9800 9799 mutex_enter(&port->fp_mutex);
9801 9800 port->fp_rnid_init = 1;
9802 9801 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9803 9802 mutex_exit(&port->fp_mutex);
9804 9803
9805 9804 /* xfer node info to userland */
9806 9805 if (ddi_copyout((void *)rnid,
9807 9806 (void *)fcio->fcio_obuf,
9808 9807 sizeof (*rnid), mode) == 0) {
9809 9808 if (fp_fcio_copyout(fcio, data,
9810 9809 mode)) {
9811 9810 rval = EFAULT;
9812 9811 }
9813 9812 } else {
9814 9813 rval = EFAULT;
9815 9814 }
9816 9815 } else {
9817 9816 rval = EIO;
9818 9817 fcio->fcio_errno = ret;
9819 9818 if (fp_fcio_copyout(fcio, data, mode)) {
9820 9819 rval = EFAULT;
9821 9820 }
9822 9821 }
9823 9822
9824 9823 kmem_free(rnid, sizeof (fc_rnid_t));
9825 9824
9826 9825 if (rval != FC_SUCCESS) {
9827 9826 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9828 9827 }
9829 9828
9830 9829 return (rval);
9831 9830 }
9832 9831
9833 9832 static int
9834 9833 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9835 9834 la_wwn_t *pwwn)
9836 9835 {
9837 9836 int rval = 0;
9838 9837 fc_remote_port_t *pd;
9839 9838 fp_cmd_t *cmd;
9840 9839 job_request_t *job;
9841 9840 la_els_rnid_acc_t *rnid_acc;
9842 9841
9843 9842 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9844 9843 if (pd == NULL) {
9845 9844 /*
9846 9845 * We can safely assume that the destination port
9847 9846 * is logged in. Either the user land will explicitly
9848 9847 * login before issuing RNID ioctl or the device would
9849 9848 * have been configured, meaning already logged in.
9850 9849 */
9851 9850
9852 9851 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9853 9852
9854 9853 return (ENXIO);
9855 9854 }
9856 9855 /*
9857 9856 * Allocate job structure and set job_code as DUMMY,
9858 9857 * because we will not go thorugh the job thread.
9859 9858 * Instead fp_sendcmd() is called directly here.
9860 9859 */
9861 9860 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9862 9861 NULL, NULL, KM_SLEEP);
9863 9862
9864 9863 ASSERT(job != NULL);
9865 9864
9866 9865 job->job_counter = 1;
9867 9866
9868 9867 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9869 9868 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9870 9869 if (cmd == NULL) {
9871 9870 fcio->fcio_errno = FC_NOMEM;
9872 9871 rval = ENOMEM;
9873 9872
9874 9873 fctl_dealloc_job(job);
9875 9874 if (fp_fcio_copyout(fcio, data, mode)) {
9876 9875 rval = EFAULT;
9877 9876 }
9878 9877
9879 9878 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9880 9879
9881 9880 return (rval);
9882 9881 }
9883 9882
9884 9883 /* Allocate memory for node id accept block */
9885 9884 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9886 9885
9887 9886 mutex_enter(&port->fp_mutex);
9888 9887 mutex_enter(&pd->pd_mutex);
9889 9888
9890 9889 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9891 9890 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9892 9891 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9893 9892 cmd->cmd_retry_count = 1;
9894 9893 cmd->cmd_ulp_pkt = NULL;
9895 9894
9896 9895 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9897 9896
9898 9897 job->job_private = (void *)rnid_acc;
9899 9898
9900 9899 pd->pd_flags = PD_ELS_IN_PROGRESS;
9901 9900
9902 9901 mutex_exit(&pd->pd_mutex);
9903 9902 mutex_exit(&port->fp_mutex);
9904 9903
9905 9904 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9906 9905 fctl_jobwait(job);
9907 9906 fcio->fcio_errno = job->job_result;
9908 9907 if (job->job_result == FC_SUCCESS) {
9909 9908 int rnid_cnt;
9910 9909 ASSERT(pd != NULL);
9911 9910 /*
9912 9911 * node id block is now available.
9913 9912 * Copy it to userland
9914 9913 */
9915 9914 ASSERT(job->job_private == (void *)rnid_acc);
9916 9915
9917 9916 /* get the response length */
9918 9917 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9919 9918 rnid_acc->hdr.cmn_len +
9920 9919 rnid_acc->hdr.specific_len;
9921 9920
9922 9921 if (fcio->fcio_olen < rnid_cnt) {
9923 9922 rval = EINVAL;
9924 9923 } else if (ddi_copyout((void *)rnid_acc,
9925 9924 (void *)fcio->fcio_obuf,
9926 9925 rnid_cnt, mode) == 0) {
9927 9926 if (fp_fcio_copyout(fcio, data,
9928 9927 mode)) {
9929 9928 rval = EFAULT;
9930 9929 }
9931 9930 } else {
9932 9931 rval = EFAULT;
9933 9932 }
9934 9933 } else {
9935 9934 rval = EIO;
9936 9935 }
9937 9936 } else {
9938 9937 rval = EIO;
9939 9938 if (pd) {
9940 9939 mutex_enter(&pd->pd_mutex);
9941 9940 pd->pd_flags = PD_IDLE;
9942 9941 mutex_exit(&pd->pd_mutex);
9943 9942 }
9944 9943 fp_free_pkt(cmd);
9945 9944 }
9946 9945
9947 9946 fctl_dealloc_job(job);
9948 9947 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9949 9948
9950 9949 if (fp_fcio_copyout(fcio, data, mode)) {
9951 9950 rval = EFAULT;
9952 9951 }
9953 9952
9954 9953 if (rval != FC_SUCCESS) {
9955 9954 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9956 9955 }
9957 9956
9958 9957 return (rval);
9959 9958 }
9960 9959
9961 9960 /*
9962 9961 * Copy out to userland
9963 9962 */
9964 9963 static int
9965 9964 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9966 9965 {
9967 9966 int rval;
9968 9967
9969 9968 #ifdef _MULTI_DATAMODEL
9970 9969 switch (ddi_model_convert_from(mode & FMODELS)) {
9971 9970 case DDI_MODEL_ILP32: {
9972 9971 struct fcio32 fcio32;
9973 9972
9974 9973 fcio32.fcio_xfer = fcio->fcio_xfer;
9975 9974 fcio32.fcio_cmd = fcio->fcio_cmd;
9976 9975 fcio32.fcio_flags = fcio->fcio_flags;
9977 9976 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9978 9977 fcio32.fcio_ilen = fcio->fcio_ilen;
9979 9978 fcio32.fcio_ibuf =
9980 9979 (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9981 9980 fcio32.fcio_olen = fcio->fcio_olen;
9982 9981 fcio32.fcio_obuf =
9983 9982 (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9984 9983 fcio32.fcio_alen = fcio->fcio_alen;
9985 9984 fcio32.fcio_abuf =
9986 9985 (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9987 9986 fcio32.fcio_errno = fcio->fcio_errno;
9988 9987
9989 9988 rval = ddi_copyout((void *)&fcio32, (void *)data,
9990 9989 sizeof (struct fcio32), mode);
9991 9990 break;
9992 9991 }
9993 9992 case DDI_MODEL_NONE:
9994 9993 rval = ddi_copyout((void *)fcio, (void *)data,
9995 9994 sizeof (fcio_t), mode);
9996 9995 break;
9997 9996 }
9998 9997 #else
9999 9998 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
10000 9999 #endif
10001 10000
10002 10001 return (rval);
10003 10002 }
10004 10003
10005 10004
10006 10005 static void
10007 10006 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
10008 10007 {
10009 10008 uint32_t listlen;
10010 10009 fc_portmap_t *changelist;
10011 10010
10012 10011 ASSERT(MUTEX_HELD(&port->fp_mutex));
10013 10012 ASSERT(port->fp_topology == FC_TOP_PT_PT);
10014 10013 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10015 10014
10016 10015 listlen = 0;
10017 10016 changelist = NULL;
10018 10017
10019 10018 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10020 10019 if (port->fp_statec_busy > 1) {
10021 10020 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10022 10021 }
10023 10022 }
10024 10023 mutex_exit(&port->fp_mutex);
10025 10024
10026 10025 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10027 10026 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10028 10027 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10029 10028 listlen, listlen, KM_SLEEP);
10030 10029
10031 10030 mutex_enter(&port->fp_mutex);
10032 10031 } else {
10033 10032 ASSERT(changelist == NULL && listlen == 0);
10034 10033 mutex_enter(&port->fp_mutex);
10035 10034 if (--port->fp_statec_busy == 0) {
10036 10035 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10037 10036 }
10038 10037 }
10039 10038 }
10040 10039
10041 10040 static int
10042 10041 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10043 10042 {
10044 10043 int rval;
10045 10044 int count;
10046 10045 int index;
10047 10046 int num_devices;
10048 10047 fc_remote_node_t *node;
10049 10048 fc_port_dev_t *devlist;
10050 10049 struct pwwn_hash *head;
10051 10050 fc_remote_port_t *pd;
10052 10051
10053 10052 ASSERT(MUTEX_HELD(&port->fp_mutex));
10054 10053
10055 10054 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10056 10055
10057 10056 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
10058 10057
10059 10058 for (count = index = 0; index < pwwn_table_size; index++) {
10060 10059 head = &port->fp_pwwn_table[index];
10061 10060 pd = head->pwwn_head;
10062 10061 while (pd != NULL) {
10063 10062 mutex_enter(&pd->pd_mutex);
10064 10063 if (pd->pd_state == PORT_DEVICE_INVALID) {
10065 10064 mutex_exit(&pd->pd_mutex);
10066 10065 pd = pd->pd_wwn_hnext;
10067 10066 continue;
10068 10067 }
10069 10068
10070 10069 devlist[count].dev_state = pd->pd_state;
10071 10070 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10072 10071 devlist[count].dev_did = pd->pd_port_id;
10073 10072 devlist[count].dev_did.priv_lilp_posit =
10074 10073 (uint8_t)(index & 0xff);
10075 10074 bcopy((caddr_t)pd->pd_fc4types,
10076 10075 (caddr_t)devlist[count].dev_type,
10077 10076 sizeof (pd->pd_fc4types));
10078 10077
10079 10078 bcopy((caddr_t)&pd->pd_port_name,
10080 10079 (caddr_t)&devlist[count].dev_pwwn,
10081 10080 sizeof (la_wwn_t));
10082 10081
10083 10082 node = pd->pd_remote_nodep;
10084 10083 mutex_exit(&pd->pd_mutex);
10085 10084
10086 10085 if (node) {
10087 10086 mutex_enter(&node->fd_mutex);
10088 10087 bcopy((caddr_t)&node->fd_node_name,
10089 10088 (caddr_t)&devlist[count].dev_nwwn,
10090 10089 sizeof (la_wwn_t));
10091 10090 mutex_exit(&node->fd_mutex);
10092 10091 }
10093 10092 count++;
10094 10093 if (count >= num_devices) {
10095 10094 goto found;
10096 10095 }
10097 10096 }
10098 10097 }
10099 10098 found:
10100 10099 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10101 10100 sizeof (count), mode)) {
10102 10101 rval = FC_FAILURE;
10103 10102 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10104 10103 sizeof (fc_port_dev_t) * num_devices, mode)) {
10105 10104 rval = FC_FAILURE;
10106 10105 } else {
10107 10106 rval = FC_SUCCESS;
10108 10107 }
10109 10108
10110 10109 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10111 10110
10112 10111 return (rval);
10113 10112 }
10114 10113
10115 10114
10116 10115 /*
10117 10116 * Handle Fabric ONLINE
10118 10117 */
10119 10118 static void
10120 10119 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10121 10120 {
10122 10121 int index;
10123 10122 int rval;
10124 10123 int dbg_count;
10125 10124 int count = 0;
10126 10125 char ww_name[17];
10127 10126 uint32_t d_id;
10128 10127 uint32_t listlen;
10129 10128 fctl_ns_req_t *ns_cmd;
10130 10129 struct pwwn_hash *head;
10131 10130 fc_remote_port_t *pd;
10132 10131 fc_remote_port_t *npd;
10133 10132 fc_portmap_t *changelist;
10134 10133
10135 10134 ASSERT(MUTEX_HELD(&port->fp_mutex));
10136 10135 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10137 10136 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10138 10137
10139 10138 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10140 10139 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10141 10140 0, KM_SLEEP);
10142 10141
10143 10142 ASSERT(ns_cmd != NULL);
10144 10143
10145 10144 ns_cmd->ns_cmd_code = NS_GID_PN;
10146 10145
10147 10146 /*
10148 10147 * Check if orphans are showing up now
10149 10148 */
10150 10149 if (port->fp_orphan_count) {
10151 10150 fc_orphan_t *orp;
10152 10151 fc_orphan_t *norp = NULL;
10153 10152 fc_orphan_t *prev = NULL;
10154 10153
10155 10154 for (orp = port->fp_orphan_list; orp; orp = norp) {
10156 10155 norp = orp->orp_next;
10157 10156 mutex_exit(&port->fp_mutex);
10158 10157 orp->orp_nscan++;
10159 10158
10160 10159 job->job_counter = 1;
10161 10160 job->job_result = FC_SUCCESS;
10162 10161
10163 10162 ((ns_req_gid_pn_t *)
10164 10163 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10165 10164 ((ns_resp_gid_pn_t *)
10166 10165 ns_cmd->ns_data_buf)->pid.port_id = 0;
10167 10166 ((ns_resp_gid_pn_t *)
10168 10167 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10169 10168
10170 10169 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10171 10170 if (rval == FC_SUCCESS) {
10172 10171 d_id =
10173 10172 BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10174 10173 pd = fp_create_remote_port_by_ns(port,
10175 10174 d_id, KM_SLEEP);
10176 10175
10177 10176 if (pd != NULL) {
10178 10177 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10179 10178
10180 10179 fp_printf(port, CE_WARN, FP_LOG_ONLY,
10181 10180 0, NULL, "N_x Port with D_ID=%x,"
10182 10181 " PWWN=%s reappeared in fabric",
10183 10182 d_id, ww_name);
10184 10183
10185 10184 mutex_enter(&port->fp_mutex);
10186 10185 if (prev) {
10187 10186 prev->orp_next = orp->orp_next;
10188 10187 } else {
10189 10188 ASSERT(orp ==
10190 10189 port->fp_orphan_list);
10191 10190 port->fp_orphan_list =
10192 10191 orp->orp_next;
10193 10192 }
10194 10193 port->fp_orphan_count--;
10195 10194 mutex_exit(&port->fp_mutex);
10196 10195 kmem_free(orp, sizeof (*orp));
10197 10196 count++;
10198 10197
10199 10198 mutex_enter(&pd->pd_mutex);
10200 10199 pd->pd_flags = PD_ELS_MARK;
10201 10200
10202 10201 mutex_exit(&pd->pd_mutex);
10203 10202 } else {
10204 10203 prev = orp;
10205 10204 }
10206 10205 } else {
10207 10206 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10208 10207 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10209 10208
10210 10209 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10211 10210 NULL,
10212 10211 " Port WWN %s removed from orphan"
10213 10212 " list after %d scans", ww_name,
10214 10213 orp->orp_nscan);
10215 10214
10216 10215 mutex_enter(&port->fp_mutex);
10217 10216 if (prev) {
10218 10217 prev->orp_next = orp->orp_next;
10219 10218 } else {
10220 10219 ASSERT(orp ==
10221 10220 port->fp_orphan_list);
10222 10221 port->fp_orphan_list =
10223 10222 orp->orp_next;
10224 10223 }
10225 10224 port->fp_orphan_count--;
10226 10225 mutex_exit(&port->fp_mutex);
10227 10226
10228 10227 kmem_free(orp, sizeof (*orp));
10229 10228 } else {
10230 10229 prev = orp;
10231 10230 }
10232 10231 }
10233 10232 mutex_enter(&port->fp_mutex);
10234 10233 }
10235 10234 }
10236 10235
10237 10236 /*
10238 10237 * Walk the Port WWN hash table, reestablish LOGIN
10239 10238 * if a LOGIN is already performed on a particular
10240 10239 * device; Any failure to LOGIN should mark the
10241 10240 * port device OLD.
10242 10241 */
10243 10242 for (index = 0; index < pwwn_table_size; index++) {
10244 10243 head = &port->fp_pwwn_table[index];
10245 10244 npd = head->pwwn_head;
10246 10245
10247 10246 while ((pd = npd) != NULL) {
10248 10247 la_wwn_t *pwwn;
10249 10248
10250 10249 npd = pd->pd_wwn_hnext;
10251 10250
10252 10251 /*
10253 10252 * Don't count in the port devices that are new
10254 10253 * unless the total number of devices visible
10255 10254 * through this port is less than FP_MAX_DEVICES
10256 10255 */
10257 10256 mutex_enter(&pd->pd_mutex);
10258 10257 if (port->fp_dev_count >= FP_MAX_DEVICES ||
10259 10258 (port->fp_options & FP_TARGET_MODE)) {
10260 10259 if (pd->pd_type == PORT_DEVICE_NEW ||
10261 10260 pd->pd_flags == PD_ELS_MARK ||
10262 10261 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10263 10262 mutex_exit(&pd->pd_mutex);
10264 10263 continue;
10265 10264 }
10266 10265 } else {
10267 10266 if (pd->pd_flags == PD_ELS_MARK ||
10268 10267 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10269 10268 mutex_exit(&pd->pd_mutex);
10270 10269 continue;
10271 10270 }
10272 10271 pd->pd_type = PORT_DEVICE_OLD;
10273 10272 }
10274 10273 count++;
10275 10274
10276 10275 /*
10277 10276 * Consult with the name server about D_ID changes
10278 10277 */
10279 10278 job->job_counter = 1;
10280 10279 job->job_result = FC_SUCCESS;
10281 10280
10282 10281 ((ns_req_gid_pn_t *)
10283 10282 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10284 10283 ((ns_resp_gid_pn_t *)
10285 10284 ns_cmd->ns_data_buf)->pid.port_id = 0;
10286 10285
10287 10286 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10288 10287 pid.priv_lilp_posit = 0;
10289 10288
10290 10289 pwwn = &pd->pd_port_name;
10291 10290 pd->pd_flags = PD_ELS_MARK;
10292 10291
10293 10292 mutex_exit(&pd->pd_mutex);
10294 10293 mutex_exit(&port->fp_mutex);
10295 10294
10296 10295 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10297 10296 if (rval != FC_SUCCESS) {
10298 10297 fc_wwn_to_str(pwwn, ww_name);
10299 10298
10300 10299 mutex_enter(&pd->pd_mutex);
10301 10300 d_id = pd->pd_port_id.port_id;
10302 10301 pd->pd_type = PORT_DEVICE_DELETE;
10303 10302 mutex_exit(&pd->pd_mutex);
10304 10303
10305 10304 FP_TRACE(FP_NHEAD1(3, 0),
10306 10305 "fp_fabric_online: PD "
10307 10306 "disappeared; d_id=%x, PWWN=%s",
10308 10307 d_id, ww_name);
10309 10308
10310 10309 FP_TRACE(FP_NHEAD2(9, 0),
10311 10310 "N_x Port with D_ID=%x, PWWN=%s"
10312 10311 " disappeared from fabric", d_id,
10313 10312 ww_name);
10314 10313
10315 10314 mutex_enter(&port->fp_mutex);
10316 10315 continue;
10317 10316 }
10318 10317
10319 10318 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10320 10319
10321 10320 mutex_enter(&port->fp_mutex);
10322 10321 mutex_enter(&pd->pd_mutex);
10323 10322 if (d_id != pd->pd_port_id.port_id) {
10324 10323 fctl_delist_did_table(port, pd);
10325 10324 fc_wwn_to_str(pwwn, ww_name);
10326 10325
10327 10326 FP_TRACE(FP_NHEAD2(9, 0),
10328 10327 "D_ID of a device with PWWN %s changed."
10329 10328 " New D_ID = %x, OLD D_ID = %x", ww_name,
10330 10329 d_id, pd->pd_port_id.port_id);
10331 10330
10332 10331 pd->pd_port_id.port_id = BE_32(d_id);
10333 10332 pd->pd_type = PORT_DEVICE_CHANGED;
10334 10333 fctl_enlist_did_table(port, pd);
10335 10334 }
10336 10335 mutex_exit(&pd->pd_mutex);
10337 10336
10338 10337 }
10339 10338 }
10340 10339
10341 10340 if (ns_cmd) {
10342 10341 fctl_free_ns_cmd(ns_cmd);
10343 10342 }
10344 10343
10345 10344 listlen = 0;
10346 10345 changelist = NULL;
10347 10346 if (count) {
10348 10347 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10349 10348 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10350 10349 mutex_exit(&port->fp_mutex);
10351 10350 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10352 10351 mutex_enter(&port->fp_mutex);
10353 10352 }
10354 10353
10355 10354 dbg_count = 0;
10356 10355
10357 10356 job->job_counter = count;
10358 10357
10359 10358 for (index = 0; index < pwwn_table_size; index++) {
10360 10359 head = &port->fp_pwwn_table[index];
10361 10360 npd = head->pwwn_head;
10362 10361
10363 10362 while ((pd = npd) != NULL) {
10364 10363 npd = pd->pd_wwn_hnext;
10365 10364
10366 10365 mutex_enter(&pd->pd_mutex);
10367 10366 if (pd->pd_flags != PD_ELS_MARK) {
10368 10367 mutex_exit(&pd->pd_mutex);
10369 10368 continue;
10370 10369 }
10371 10370
10372 10371 dbg_count++;
10373 10372
10374 10373 /*
10375 10374 * If it is already marked deletion, nothing
10376 10375 * else to do.
10377 10376 */
10378 10377 if (pd->pd_type == PORT_DEVICE_DELETE) {
10379 10378 pd->pd_type = PORT_DEVICE_OLD;
10380 10379
10381 10380 mutex_exit(&pd->pd_mutex);
10382 10381 mutex_exit(&port->fp_mutex);
10383 10382 fp_jobdone(job);
10384 10383 mutex_enter(&port->fp_mutex);
10385 10384
10386 10385 continue;
10387 10386 }
10388 10387
10389 10388 /*
10390 10389 * If it is freshly discovered out of
10391 10390 * the orphan list, nothing else to do
10392 10391 */
10393 10392 if (pd->pd_type == PORT_DEVICE_NEW) {
10394 10393 pd->pd_flags = PD_IDLE;
10395 10394
10396 10395 mutex_exit(&pd->pd_mutex);
10397 10396 mutex_exit(&port->fp_mutex);
10398 10397 fp_jobdone(job);
10399 10398 mutex_enter(&port->fp_mutex);
10400 10399
10401 10400 continue;
10402 10401 }
10403 10402
10404 10403 pd->pd_flags = PD_IDLE;
10405 10404 d_id = pd->pd_port_id.port_id;
10406 10405
10407 10406 /*
10408 10407 * Explicitly mark all devices OLD; successful
10409 10408 * PLOGI should reset this to either NO_CHANGE
10410 10409 * or CHANGED.
10411 10410 */
10412 10411 if (pd->pd_type != PORT_DEVICE_CHANGED) {
10413 10412 pd->pd_type = PORT_DEVICE_OLD;
10414 10413 }
10415 10414
10416 10415 mutex_exit(&pd->pd_mutex);
10417 10416 mutex_exit(&port->fp_mutex);
10418 10417
10419 10418 rval = fp_port_login(port, d_id, job,
10420 10419 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10421 10420
10422 10421 if (rval != FC_SUCCESS) {
10423 10422 fp_jobdone(job);
10424 10423 }
10425 10424 mutex_enter(&port->fp_mutex);
10426 10425 }
10427 10426 }
10428 10427 mutex_exit(&port->fp_mutex);
10429 10428
10430 10429 ASSERT(dbg_count == count);
10431 10430 fp_jobwait(job);
10432 10431
10433 10432 mutex_enter(&port->fp_mutex);
10434 10433
10435 10434 ASSERT(port->fp_statec_busy > 0);
10436 10435 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10437 10436 if (port->fp_statec_busy > 1) {
10438 10437 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10439 10438 }
10440 10439 }
10441 10440 mutex_exit(&port->fp_mutex);
10442 10441 } else {
10443 10442 ASSERT(port->fp_statec_busy > 0);
10444 10443 if (port->fp_statec_busy > 1) {
10445 10444 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10446 10445 }
10447 10446 mutex_exit(&port->fp_mutex);
10448 10447 }
10449 10448
10450 10449 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10451 10450 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10452 10451
10453 10452 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10454 10453 listlen, listlen, KM_SLEEP);
10455 10454
10456 10455 mutex_enter(&port->fp_mutex);
10457 10456 } else {
10458 10457 ASSERT(changelist == NULL && listlen == 0);
10459 10458 mutex_enter(&port->fp_mutex);
10460 10459 if (--port->fp_statec_busy == 0) {
10461 10460 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10462 10461 }
10463 10462 }
10464 10463 }
10465 10464
10466 10465
10467 10466 /*
10468 10467 * Fill out device list for userland ioctl in private loop
10469 10468 */
10470 10469 static int
10471 10470 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10472 10471 {
10473 10472 int rval;
10474 10473 int count;
10475 10474 int index;
10476 10475 int num_devices;
10477 10476 fc_remote_node_t *node;
10478 10477 fc_port_dev_t *devlist;
10479 10478 int lilp_device_count;
10480 10479 fc_lilpmap_t *lilp_map;
10481 10480 uchar_t *alpa_list;
10482 10481
10483 10482 ASSERT(MUTEX_HELD(&port->fp_mutex));
10484 10483
10485 10484 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10486 10485 if (port->fp_total_devices > port->fp_dev_count &&
10487 10486 num_devices >= port->fp_total_devices) {
10488 10487 job_request_t *job;
10489 10488
10490 10489 mutex_exit(&port->fp_mutex);
10491 10490 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10492 10491 job->job_counter = 1;
10493 10492
10494 10493 mutex_enter(&port->fp_mutex);
10495 10494 fp_get_loopmap(port, job);
10496 10495 mutex_exit(&port->fp_mutex);
10497 10496
10498 10497 fp_jobwait(job);
10499 10498 fctl_dealloc_job(job);
10500 10499 } else {
10501 10500 mutex_exit(&port->fp_mutex);
10502 10501 }
10503 10502 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10504 10503
10505 10504 mutex_enter(&port->fp_mutex);
10506 10505
10507 10506 /*
10508 10507 * Applications are accustomed to getting the device list in
10509 10508 * LILP map order. The HBA firmware usually returns the device
10510 10509 * map in the LILP map order and diagnostic applications would
10511 10510 * prefer to receive in the device list in that order too
10512 10511 */
10513 10512 lilp_map = &port->fp_lilp_map;
10514 10513 alpa_list = &lilp_map->lilp_alpalist[0];
10515 10514
10516 10515 /*
10517 10516 * the length field corresponds to the offset in the LILP frame
10518 10517 * which begins with 1. The thing to note here is that the
10519 10518 * lilp_device_count is 1 more than fp->fp_total_devices since
10520 10519 * the host adapter's alpa also shows up in the lilp map. We
10521 10520 * don't however return details of the host adapter since
10522 10521 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10523 10522 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10524 10523 * ioctl to obtain details about the host adapter port.
10525 10524 */
10526 10525 lilp_device_count = lilp_map->lilp_length;
10527 10526
10528 10527 for (count = index = 0; index < lilp_device_count &&
10529 10528 count < num_devices; index++) {
10530 10529 uint32_t d_id;
10531 10530 fc_remote_port_t *pd;
10532 10531
10533 10532 d_id = alpa_list[index];
10534 10533
10535 10534 mutex_exit(&port->fp_mutex);
10536 10535 pd = fctl_get_remote_port_by_did(port, d_id);
10537 10536 mutex_enter(&port->fp_mutex);
10538 10537
10539 10538 if (pd != NULL) {
10540 10539 mutex_enter(&pd->pd_mutex);
10541 10540
10542 10541 if (pd->pd_state == PORT_DEVICE_INVALID) {
10543 10542 mutex_exit(&pd->pd_mutex);
10544 10543 continue;
10545 10544 }
10546 10545
10547 10546 devlist[count].dev_state = pd->pd_state;
10548 10547 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10549 10548 devlist[count].dev_did = pd->pd_port_id;
10550 10549 devlist[count].dev_did.priv_lilp_posit =
10551 10550 (uint8_t)(index & 0xff);
10552 10551 bcopy((caddr_t)pd->pd_fc4types,
10553 10552 (caddr_t)devlist[count].dev_type,
10554 10553 sizeof (pd->pd_fc4types));
10555 10554
10556 10555 bcopy((caddr_t)&pd->pd_port_name,
10557 10556 (caddr_t)&devlist[count].dev_pwwn,
10558 10557 sizeof (la_wwn_t));
10559 10558
10560 10559 node = pd->pd_remote_nodep;
10561 10560 mutex_exit(&pd->pd_mutex);
10562 10561
10563 10562 if (node) {
10564 10563 mutex_enter(&node->fd_mutex);
10565 10564 bcopy((caddr_t)&node->fd_node_name,
10566 10565 (caddr_t)&devlist[count].dev_nwwn,
10567 10566 sizeof (la_wwn_t));
10568 10567 mutex_exit(&node->fd_mutex);
10569 10568 }
10570 10569 count++;
10571 10570 }
10572 10571 }
10573 10572
10574 10573 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10575 10574 sizeof (count), mode)) {
10576 10575 rval = FC_FAILURE;
10577 10576 }
10578 10577
10579 10578 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10580 10579 sizeof (fc_port_dev_t) * num_devices, mode)) {
10581 10580 rval = FC_FAILURE;
10582 10581 } else {
10583 10582 rval = FC_SUCCESS;
10584 10583 }
10585 10584
10586 10585 kmem_free(devlist, sizeof (*devlist) * num_devices);
10587 10586 ASSERT(MUTEX_HELD(&port->fp_mutex));
10588 10587
10589 10588 return (rval);
10590 10589 }
10591 10590
10592 10591
10593 10592 /*
10594 10593 * Completion function for responses to unsolicited commands
10595 10594 */
10596 10595 static void
10597 10596 fp_unsol_intr(fc_packet_t *pkt)
10598 10597 {
10599 10598 fp_cmd_t *cmd;
10600 10599 fc_local_port_t *port;
10601 10600
10602 10601 cmd = pkt->pkt_ulp_private;
10603 10602 port = cmd->cmd_port;
10604 10603
10605 10604 mutex_enter(&port->fp_mutex);
10606 10605 port->fp_out_fpcmds--;
10607 10606 mutex_exit(&port->fp_mutex);
10608 10607
10609 10608 if (pkt->pkt_state != FC_PKT_SUCCESS) {
10610 10609 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10611 10610 "couldn't post response to unsolicited request;"
10612 10611 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10613 10612 pkt->pkt_resp_fhdr.rx_id);
10614 10613 }
10615 10614
10616 10615 if (cmd == port->fp_els_resp_pkt) {
10617 10616 mutex_enter(&port->fp_mutex);
10618 10617 port->fp_els_resp_pkt_busy = 0;
10619 10618 mutex_exit(&port->fp_mutex);
10620 10619 return;
10621 10620 }
10622 10621
10623 10622 fp_free_pkt(cmd);
10624 10623 }
10625 10624
10626 10625
10627 10626 /*
10628 10627 * solicited LINIT ELS completion function
10629 10628 */
10630 10629 static void
10631 10630 fp_linit_intr(fc_packet_t *pkt)
10632 10631 {
10633 10632 fp_cmd_t *cmd;
10634 10633 job_request_t *job;
10635 10634 fc_linit_resp_t acc;
10636 10635 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10637 10636
10638 10637 cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10639 10638
10640 10639 mutex_enter(&cmd->cmd_port->fp_mutex);
10641 10640 cmd->cmd_port->fp_out_fpcmds--;
10642 10641 mutex_exit(&cmd->cmd_port->fp_mutex);
10643 10642
10644 10643 if (FP_IS_PKT_ERROR(pkt)) {
10645 10644 (void) fp_common_intr(pkt, 1);
10646 10645 return;
10647 10646 }
10648 10647
10649 10648 job = cmd->cmd_job;
10650 10649
10651 10650 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10652 10651 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10653 10652 if (acc.status != FC_LINIT_SUCCESS) {
10654 10653 job->job_result = FC_FAILURE;
10655 10654 } else {
10656 10655 job->job_result = FC_SUCCESS;
10657 10656 }
10658 10657
10659 10658 fp_iodone(cmd);
10660 10659 }
10661 10660
10662 10661
10663 10662 /*
10664 10663 * Decode the unsolicited request; For FC-4 Device and Link data frames
10665 10664 * notify the registered ULP of this FC-4 type right here. For Unsolicited
10666 10665 * ELS requests, submit a request to the job_handler thread to work on it.
10667 10666 * The intent is to act quickly on the FC-4 unsolicited link and data frames
10668 10667 * and save much of the interrupt time processing of unsolicited ELS requests
10669 10668 * and hand it off to the job_handler thread.
10670 10669 */
10671 10670 static void
10672 10671 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10673 10672 {
10674 10673 uchar_t r_ctl;
10675 10674 uchar_t ls_code;
10676 10675 uint32_t s_id;
10677 10676 uint32_t rscn_count = FC_INVALID_RSCN_COUNT;
10678 10677 uint32_t cb_arg;
10679 10678 fp_cmd_t *cmd;
10680 10679 fc_local_port_t *port;
10681 10680 job_request_t *job;
10682 10681 fc_remote_port_t *pd;
10683 10682
10684 10683 port = port_handle;
10685 10684
10686 10685 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10687 10686 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10688 10687 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10689 10688 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10690 10689 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10691 10690 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10692 10691 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10693 10692 buf->ub_buffer[0]);
10694 10693
10695 10694 if (type & 0x80000000) {
10696 10695 /*
10697 10696 * Huh ? Nothing much can be done without
10698 10697 * a valid buffer. So just exit.
10699 10698 */
10700 10699 return;
10701 10700 }
10702 10701 /*
10703 10702 * If the unsolicited interrupts arrive while it isn't
10704 10703 * safe to handle unsolicited callbacks; Drop them, yes,
10705 10704 * drop them on the floor
10706 10705 */
10707 10706 mutex_enter(&port->fp_mutex);
10708 10707 port->fp_active_ubs++;
10709 10708 if ((port->fp_soft_state &
10710 10709 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10711 10710 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10712 10711
10713 10712 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10714 10713 "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10715 10714 "seq_id=%x, ox_id=%x, rx_id=%x"
10716 10715 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10717 10716 buf->ub_frame.type, buf->ub_frame.seq_id,
10718 10717 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10719 10718
10720 10719 ASSERT(port->fp_active_ubs > 0);
10721 10720 if (--(port->fp_active_ubs) == 0) {
10722 10721 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10723 10722 }
10724 10723
10725 10724 mutex_exit(&port->fp_mutex);
10726 10725
10727 10726 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10728 10727 1, &buf->ub_token);
10729 10728
10730 10729 return;
10731 10730 }
10732 10731
10733 10732 r_ctl = buf->ub_frame.r_ctl;
10734 10733 s_id = buf->ub_frame.s_id;
10735 10734 if (port->fp_active_ubs == 1) {
10736 10735 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10737 10736 }
10738 10737
10739 10738 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10740 10739 port->fp_statec_busy) {
10741 10740 mutex_exit(&port->fp_mutex);
10742 10741 pd = fctl_get_remote_port_by_did(port, s_id);
10743 10742 if (pd) {
10744 10743 mutex_enter(&pd->pd_mutex);
10745 10744 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10746 10745 FP_TRACE(FP_NHEAD1(3, 0),
10747 10746 "LOGO for LOGGED IN D_ID %x",
10748 10747 buf->ub_frame.s_id);
10749 10748 pd->pd_state = PORT_DEVICE_VALID;
10750 10749 }
10751 10750 mutex_exit(&pd->pd_mutex);
10752 10751 }
10753 10752
10754 10753 mutex_enter(&port->fp_mutex);
10755 10754 ASSERT(port->fp_active_ubs > 0);
10756 10755 if (--(port->fp_active_ubs) == 0) {
10757 10756 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10758 10757 }
10759 10758 mutex_exit(&port->fp_mutex);
10760 10759
10761 10760 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10762 10761 1, &buf->ub_token);
10763 10762
10764 10763 FP_TRACE(FP_NHEAD1(3, 0),
10765 10764 "fp_unsol_cb() bailing out LOGO for D_ID %x",
10766 10765 buf->ub_frame.s_id);
10767 10766 return;
10768 10767 }
10769 10768
10770 10769 if (port->fp_els_resp_pkt_busy == 0) {
10771 10770 if (r_ctl == R_CTL_ELS_REQ) {
10772 10771 ls_code = buf->ub_buffer[0];
10773 10772
10774 10773 switch (ls_code) {
10775 10774 case LA_ELS_PLOGI:
10776 10775 case LA_ELS_FLOGI:
10777 10776 port->fp_els_resp_pkt_busy = 1;
10778 10777 mutex_exit(&port->fp_mutex);
10779 10778 fp_i_handle_unsol_els(port, buf);
10780 10779
10781 10780 mutex_enter(&port->fp_mutex);
10782 10781 ASSERT(port->fp_active_ubs > 0);
10783 10782 if (--(port->fp_active_ubs) == 0) {
10784 10783 port->fp_soft_state &=
10785 10784 ~FP_SOFT_IN_UNSOL_CB;
10786 10785 }
10787 10786 mutex_exit(&port->fp_mutex);
10788 10787 port->fp_fca_tran->fca_ub_release(
10789 10788 port->fp_fca_handle, 1, &buf->ub_token);
10790 10789
10791 10790 return;
10792 10791 case LA_ELS_RSCN:
10793 10792 if (++(port)->fp_rscn_count ==
10794 10793 FC_INVALID_RSCN_COUNT) {
10795 10794 ++(port)->fp_rscn_count;
10796 10795 }
10797 10796 rscn_count = port->fp_rscn_count;
10798 10797 break;
10799 10798
10800 10799 default:
10801 10800 break;
10802 10801 }
10803 10802 }
10804 10803 } else if ((r_ctl == R_CTL_ELS_REQ) &&
10805 10804 (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10806 10805 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10807 10806 ++port->fp_rscn_count;
10808 10807 }
10809 10808 rscn_count = port->fp_rscn_count;
10810 10809 }
10811 10810
10812 10811 mutex_exit(&port->fp_mutex);
10813 10812
10814 10813 switch (r_ctl & R_CTL_ROUTING) {
10815 10814 case R_CTL_DEVICE_DATA:
10816 10815 /*
10817 10816 * If the unsolicited buffer is a CT IU,
10818 10817 * have the job_handler thread work on it.
10819 10818 */
10820 10819 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10821 10820 break;
10822 10821 }
10823 10822 /* FALLTHROUGH */
10824 10823
10825 10824 case R_CTL_FC4_SVC: {
10826 10825 int sendup = 0;
10827 10826
10828 10827 /*
10829 10828 * If a LOGIN isn't performed before this request
10830 10829 * shut the door on this port with a reply that a
10831 10830 * LOGIN is required. We make an exception however
10832 10831 * for IP broadcast packets and pass them through
10833 10832 * to the IP ULP(s) to handle broadcast requests.
10834 10833 * This is not a problem for private loop devices
10835 10834 * but for fabric topologies we don't log into the
10836 10835 * remote ports during port initialization and
10837 10836 * the ULPs need to log into requesting ports on
10838 10837 * demand.
10839 10838 */
10840 10839 pd = fctl_get_remote_port_by_did(port, s_id);
10841 10840 if (pd) {
10842 10841 mutex_enter(&pd->pd_mutex);
10843 10842 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10844 10843 sendup++;
10845 10844 }
10846 10845 mutex_exit(&pd->pd_mutex);
10847 10846 } else if ((pd == NULL) &&
10848 10847 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10849 10848 (buf->ub_frame.d_id == 0xffffff ||
10850 10849 buf->ub_frame.d_id == 0x00)) {
10851 10850 /* brodacst IP frame - so sendup via job thread */
10852 10851 break;
10853 10852 }
10854 10853
10855 10854 /*
10856 10855 * Send all FC4 services via job thread too
10857 10856 */
10858 10857 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10859 10858 break;
10860 10859 }
10861 10860
10862 10861 if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10863 10862 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10864 10863 return;
10865 10864 }
10866 10865
10867 10866 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10868 10867 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10869 10868 0, KM_NOSLEEP, pd);
10870 10869 if (cmd != NULL) {
10871 10870 fp_els_rjt_init(port, cmd, buf,
10872 10871 FC_ACTION_NON_RETRYABLE,
10873 10872 FC_REASON_LOGIN_REQUIRED, NULL);
10874 10873
10875 10874 if (fp_sendcmd(port, cmd,
10876 10875 port->fp_fca_handle) != FC_SUCCESS) {
10877 10876 fp_free_pkt(cmd);
10878 10877 }
10879 10878 }
10880 10879 }
10881 10880
10882 10881 mutex_enter(&port->fp_mutex);
10883 10882 ASSERT(port->fp_active_ubs > 0);
10884 10883 if (--(port->fp_active_ubs) == 0) {
10885 10884 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10886 10885 }
10887 10886 mutex_exit(&port->fp_mutex);
10888 10887 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10889 10888 1, &buf->ub_token);
10890 10889
10891 10890 return;
10892 10891 }
10893 10892
10894 10893 default:
10895 10894 break;
10896 10895 }
10897 10896
10898 10897 /*
10899 10898 * Submit a Request to the job_handler thread to work
10900 10899 * on the unsolicited request. The potential side effect
10901 10900 * of this is that the unsolicited buffer takes a little
10902 10901 * longer to get released but we save interrupt time in
10903 10902 * the bargain.
10904 10903 */
10905 10904 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10906 10905
10907 10906 /*
10908 10907 * One way that the rscn_count will get used is described below :
10909 10908 *
10910 10909 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10911 10910 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10912 10911 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10913 10912 * by overloading the job_cb_arg to pass the rscn_count
10914 10913 * 4. When one of the routines processing the RSCN picks it up (ex:
10915 10914 * fp_validate_rscn_page()), it passes this count in the map
10916 10915 * structure (as part of the map_rscn_info structure member) to the
10917 10916 * ULPs.
10918 10917 * 5. When ULPs make calls back to the transport (example interfaces for
10919 10918 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10920 10919 * can now pass back this count as part of the fc_packet's
10921 10920 * pkt_ulp_rscn_count member. fcp does this currently.
10922 10921 * 6. When transport gets a call to transport a command on the wire, it
10923 10922 * will check to see if there is a valid pkt_ulp_rsvd1 field in the
10924 10923 * fc_packet. If there is, it will match that info with the current
10925 10924 * rscn_count on that instance of the port. If they don't match up
10926 10925 * then there was a newer RSCN. The ULP gets back an error code which
10927 10926 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10928 10927 * 7. At this point the ULP is free to make up its own mind as to how to
10929 10928 * handle this. Currently, fcp will reset its retry counters and keep
10930 10929 * retrying the operation it was doing in anticipation of getting a
10931 10930 * new state change call back for the new RSCN.
10932 10931 */
10933 10932 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10934 10933 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10935 10934 if (job == NULL) {
10936 10935 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10937 10936 "couldn't submit a job to the thread, failing..");
10938 10937
10939 10938 mutex_enter(&port->fp_mutex);
10940 10939
10941 10940 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10942 10941 --port->fp_rscn_count;
10943 10942 }
10944 10943
10945 10944 ASSERT(port->fp_active_ubs > 0);
10946 10945 if (--(port->fp_active_ubs) == 0) {
10947 10946 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10948 10947 }
10949 10948
10950 10949 mutex_exit(&port->fp_mutex);
10951 10950 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10952 10951 1, &buf->ub_token);
10953 10952
10954 10953 return;
10955 10954 }
10956 10955 job->job_private = (void *)buf;
10957 10956 fctl_enque_job(port, job);
10958 10957 }
10959 10958
10960 10959
10961 10960 /*
10962 10961 * Handle unsolicited requests
10963 10962 */
10964 10963 static void
10965 10964 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10966 10965 job_request_t *job)
10967 10966 {
10968 10967 uchar_t r_ctl;
10969 10968 uchar_t ls_code;
10970 10969 uint32_t s_id;
10971 10970 fp_cmd_t *cmd;
10972 10971 fc_remote_port_t *pd;
10973 10972 fp_unsol_spec_t *ub_spec;
10974 10973
10975 10974 r_ctl = buf->ub_frame.r_ctl;
10976 10975 s_id = buf->ub_frame.s_id;
10977 10976
10978 10977 switch (r_ctl & R_CTL_ROUTING) {
10979 10978 case R_CTL_EXTENDED_SVC:
10980 10979 if (r_ctl != R_CTL_ELS_REQ) {
10981 10980 break;
10982 10981 }
10983 10982
10984 10983 ls_code = buf->ub_buffer[0];
10985 10984 switch (ls_code) {
10986 10985 case LA_ELS_LOGO:
10987 10986 case LA_ELS_ADISC:
10988 10987 case LA_ELS_PRLO:
10989 10988 pd = fctl_get_remote_port_by_did(port, s_id);
10990 10989 if (pd == NULL) {
10991 10990 if (!FC_IS_REAL_DEVICE(s_id)) {
10992 10991 break;
10993 10992 }
10994 10993 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10995 10994 break;
10996 10995 }
10997 10996 if ((cmd = fp_alloc_pkt(port,
10998 10997 sizeof (la_els_rjt_t), 0, KM_SLEEP,
10999 10998 NULL)) == NULL) {
11000 10999 /*
11001 11000 * Can this actually fail when
11002 11001 * given KM_SLEEP? (Could be used
11003 11002 * this way in a number of places.)
11004 11003 */
11005 11004 break;
11006 11005 }
11007 11006
11008 11007 fp_els_rjt_init(port, cmd, buf,
11009 11008 FC_ACTION_NON_RETRYABLE,
11010 11009 FC_REASON_INVALID_LINK_CTRL, job);
11011 11010
11012 11011 if (fp_sendcmd(port, cmd,
11013 11012 port->fp_fca_handle) != FC_SUCCESS) {
11014 11013 fp_free_pkt(cmd);
11015 11014 }
11016 11015
11017 11016 break;
11018 11017 }
11019 11018 if (ls_code == LA_ELS_LOGO) {
11020 11019 fp_handle_unsol_logo(port, buf, pd, job);
11021 11020 } else if (ls_code == LA_ELS_ADISC) {
11022 11021 fp_handle_unsol_adisc(port, buf, pd, job);
11023 11022 } else {
11024 11023 fp_handle_unsol_prlo(port, buf, pd, job);
11025 11024 }
11026 11025 break;
11027 11026
11028 11027 case LA_ELS_PLOGI:
11029 11028 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
11030 11029 break;
11031 11030
11032 11031 case LA_ELS_FLOGI:
11033 11032 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
11034 11033 break;
11035 11034
11036 11035 case LA_ELS_RSCN:
11037 11036 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
11038 11037 break;
11039 11038
11040 11039 default:
11041 11040 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11042 11041 ub_spec->port = port;
11043 11042 ub_spec->buf = buf;
11044 11043
11045 11044 (void) taskq_dispatch(port->fp_taskq,
11046 11045 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11047 11046 return;
11048 11047 }
11049 11048 break;
11050 11049
11051 11050 case R_CTL_BASIC_SVC:
11052 11051 /*
11053 11052 * The unsolicited basic link services could be ABTS
11054 11053 * and RMC (Or even a NOP). Just BA_RJT them until
11055 11054 * such time there arises a need to handle them more
11056 11055 * carefully.
11057 11056 */
11058 11057 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11059 11058 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
11060 11059 0, KM_SLEEP, NULL);
11061 11060 if (cmd != NULL) {
11062 11061 fp_ba_rjt_init(port, cmd, buf, job);
11063 11062 if (fp_sendcmd(port, cmd,
11064 11063 port->fp_fca_handle) != FC_SUCCESS) {
11065 11064 fp_free_pkt(cmd);
11066 11065 }
11067 11066 }
11068 11067 }
11069 11068 break;
11070 11069
11071 11070 case R_CTL_DEVICE_DATA:
11072 11071 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11073 11072 /*
11074 11073 * Mostly this is of type FC_TYPE_FC_SERVICES.
11075 11074 * As we don't like any Unsolicited FC services
11076 11075 * requests, we would do well to RJT them as
11077 11076 * well.
11078 11077 */
11079 11078 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11080 11079 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11081 11080 0, KM_SLEEP, NULL);
11082 11081 if (cmd != NULL) {
11083 11082 fp_els_rjt_init(port, cmd, buf,
11084 11083 FC_ACTION_NON_RETRYABLE,
11085 11084 FC_REASON_INVALID_LINK_CTRL, job);
11086 11085
11087 11086 if (fp_sendcmd(port, cmd,
11088 11087 port->fp_fca_handle) !=
11089 11088 FC_SUCCESS) {
11090 11089 fp_free_pkt(cmd);
11091 11090 }
11092 11091 }
11093 11092 }
11094 11093 break;
11095 11094 }
11096 11095 /* FALLTHROUGH */
11097 11096
11098 11097 case R_CTL_FC4_SVC:
11099 11098 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11100 11099 ub_spec->port = port;
11101 11100 ub_spec->buf = buf;
11102 11101
11103 11102 (void) taskq_dispatch(port->fp_taskq,
11104 11103 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11105 11104 return;
11106 11105
11107 11106 case R_CTL_LINK_CTL:
11108 11107 /*
11109 11108 * Turn deaf ear on unsolicited link control frames.
11110 11109 * Typical unsolicited link control Frame is an LCR
11111 11110 * (to reset End to End credit to the default login
11112 11111 * value and abort current sequences for all classes)
11113 11112 * An intelligent microcode/firmware should handle
11114 11113 * this transparently at its level and not pass all
11115 11114 * the way up here.
11116 11115 *
11117 11116 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11118 11117 * or F_BSY. P_RJT is chosen to be the most appropriate
11119 11118 * at this time.
11120 11119 */
11121 11120 /* FALLTHROUGH */
11122 11121
11123 11122 default:
11124 11123 /*
11125 11124 * Just reject everything else as an invalid request.
11126 11125 */
11127 11126 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11128 11127 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11129 11128 0, KM_SLEEP, NULL);
11130 11129 if (cmd != NULL) {
11131 11130 fp_els_rjt_init(port, cmd, buf,
11132 11131 FC_ACTION_NON_RETRYABLE,
11133 11132 FC_REASON_INVALID_LINK_CTRL, job);
11134 11133
11135 11134 if (fp_sendcmd(port, cmd,
11136 11135 port->fp_fca_handle) != FC_SUCCESS) {
11137 11136 fp_free_pkt(cmd);
11138 11137 }
11139 11138 }
11140 11139 }
11141 11140 break;
11142 11141 }
11143 11142
11144 11143 mutex_enter(&port->fp_mutex);
11145 11144 ASSERT(port->fp_active_ubs > 0);
11146 11145 if (--(port->fp_active_ubs) == 0) {
11147 11146 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11148 11147 }
11149 11148 mutex_exit(&port->fp_mutex);
11150 11149 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11151 11150 1, &buf->ub_token);
11152 11151 }
11153 11152
11154 11153
11155 11154 /*
11156 11155 * Prepare a BA_RJT and send it over.
11157 11156 */
11158 11157 static void
11159 11158 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11160 11159 job_request_t *job)
11161 11160 {
11162 11161 fc_packet_t *pkt;
11163 11162 la_ba_rjt_t payload;
11164 11163
11165 11164 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11166 11165
11167 11166 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11168 11167 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11169 11168 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11170 11169 cmd->cmd_retry_count = 1;
11171 11170 cmd->cmd_ulp_pkt = NULL;
11172 11171
11173 11172 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11174 11173 cmd->cmd_job = job;
11175 11174
11176 11175 pkt = &cmd->cmd_pkt;
11177 11176
11178 11177 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11179 11178
11180 11179 payload.reserved = 0;
11181 11180 payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11182 11181 payload.explanation = FC_EXPLN_NONE;
11183 11182 payload.vendor = 0;
11184 11183
11185 11184 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11186 11185 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11187 11186 }
11188 11187
11189 11188
11190 11189 /*
11191 11190 * Prepare an LS_RJT and send it over
11192 11191 */
11193 11192 static void
11194 11193 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11195 11194 uchar_t action, uchar_t reason, job_request_t *job)
11196 11195 {
11197 11196 fc_packet_t *pkt;
11198 11197 la_els_rjt_t payload;
11199 11198
11200 11199 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11201 11200
11202 11201 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11203 11202 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11204 11203 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11205 11204 cmd->cmd_retry_count = 1;
11206 11205 cmd->cmd_ulp_pkt = NULL;
11207 11206
11208 11207 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11209 11208 cmd->cmd_job = job;
11210 11209
11211 11210 pkt = &cmd->cmd_pkt;
11212 11211
11213 11212 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11214 11213
11215 11214 payload.ls_code.ls_code = LA_ELS_RJT;
11216 11215 payload.ls_code.mbz = 0;
11217 11216 payload.action = action;
11218 11217 payload.reason = reason;
11219 11218 payload.reserved = 0;
11220 11219 payload.vu = 0;
11221 11220
11222 11221 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11223 11222 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11224 11223 }
11225 11224
11226 11225 /*
11227 11226 * Function: fp_prlo_acc_init
11228 11227 *
11229 11228 * Description: Initializes an Link Service Accept for a PRLO.
11230 11229 *
11231 11230 * Arguments: *port Local port through which the PRLO was
11232 11231 * received.
11233 11232 * cmd Command that will carry the accept.
11234 11233 * *buf Unsolicited buffer containing the PRLO
11235 11234 * request.
11236 11235 * job Job request.
11237 11236 * sleep Allocation mode.
11238 11237 *
11239 11238 * Return Value: *cmd Command containing the response.
11240 11239 *
11241 11240 * Context: Depends on the parameter sleep.
11242 11241 */
11243 11242 fp_cmd_t *
11244 11243 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11245 11244 fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11246 11245 {
11247 11246 fp_cmd_t *cmd;
11248 11247 fc_packet_t *pkt;
11249 11248 la_els_prlo_t *req;
11250 11249 size_t len;
11251 11250 uint16_t flags;
11252 11251
11253 11252 req = (la_els_prlo_t *)buf->ub_buffer;
11254 11253 len = (size_t)ntohs(req->payload_length);
11255 11254
11256 11255 /*
11257 11256 * The payload of the accept to a PRLO has to be the exact match of
11258 11257 * the payload of the request (at the exception of the code).
11259 11258 */
11260 11259 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11261 11260
11262 11261 if (cmd) {
11263 11262 /*
11264 11263 * The fp command was successfully allocated.
11265 11264 */
11266 11265 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11267 11266 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11268 11267 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11269 11268 cmd->cmd_retry_count = 1;
11270 11269 cmd->cmd_ulp_pkt = NULL;
11271 11270
11272 11271 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11273 11272 cmd->cmd_job = job;
11274 11273
11275 11274 pkt = &cmd->cmd_pkt;
11276 11275
11277 11276 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11278 11277 FC_TYPE_EXTENDED_LS);
11279 11278
11280 11279 /* The code is overwritten for the copy. */
11281 11280 req->ls_code = LA_ELS_ACC;
11282 11281 /* Response code is set. */
11283 11282 flags = ntohs(req->flags);
11284 11283 flags &= ~SP_RESP_CODE_MASK;
11285 11284 flags |= SP_RESP_CODE_REQ_EXECUTED;
11286 11285 req->flags = htons(flags);
11287 11286
11288 11287 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11289 11288 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11290 11289 }
11291 11290 return (cmd);
11292 11291 }
11293 11292
11294 11293 /*
11295 11294 * Prepare an ACC response to an ELS request
11296 11295 */
11297 11296 static void
11298 11297 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11299 11298 job_request_t *job)
11300 11299 {
11301 11300 fc_packet_t *pkt;
11302 11301 ls_code_t payload;
11303 11302
11304 11303 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11305 11304 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11306 11305 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11307 11306 cmd->cmd_retry_count = 1;
11308 11307 cmd->cmd_ulp_pkt = NULL;
11309 11308
11310 11309 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11311 11310 cmd->cmd_job = job;
11312 11311
11313 11312 pkt = &cmd->cmd_pkt;
11314 11313
11315 11314 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11316 11315
11317 11316 payload.ls_code = LA_ELS_ACC;
11318 11317 payload.mbz = 0;
11319 11318
11320 11319 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11321 11320 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11322 11321 }
11323 11322
11324 11323 /*
11325 11324 * Unsolicited PRLO handler
11326 11325 *
11327 11326 * A Process Logout should be handled by the ULP that established it. However,
11328 11327 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens
11329 11328 * when a device implicitly logs out an initiator (for whatever reason) and
11330 11329 * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11331 11330 * The logical thing to do for the device would be to send a LOGO in response
11332 11331 * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11333 11332 * a PRLO instead.
11334 11333 *
11335 11334 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11336 11335 * think that the Port Login has been lost. If we follow the Fibre Channel
11337 11336 * protocol to the letter a PRLI should be sent after accepting the PRLO. If
11338 11337 * the Port Login has also been lost, the remote port will reject the PRLI
11339 11338 * indicating that we must PLOGI first. The initiator will then turn around and
11340 11339 * send a PLOGI. The way Leadville is layered and the way the ULP interface
11341 11340 * is defined doesn't allow this scenario to be followed easily. If FCP were to
11342 11341 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11343 11342 * needed would be received by FCP. FCP would have, then, to tell the transport
11344 11343 * (fp) to PLOGI. The problem is, the transport would still think the Port
11345 11344 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11346 11345 * if you think it's not necessary". To work around that difficulty, the PRLO
11347 11346 * is treated by the transport as a LOGO. The downside to it is a Port Login
11348 11347 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11349 11348 * has nothing to do with the PRLO) may be impacted. However, this is a
11350 11349 * scenario very unlikely to happen. As of today the only ULP in Leadville
11351 11350 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be
11352 11351 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11353 11352 * unlikely).
11354 11353 */
11355 11354 static void
11356 11355 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11357 11356 fc_remote_port_t *pd, job_request_t *job)
11358 11357 {
11359 11358 int busy;
11360 11359 int rval;
11361 11360 int retain;
11362 11361 fp_cmd_t *cmd;
11363 11362 fc_portmap_t *listptr;
11364 11363 boolean_t tolerance;
11365 11364 la_els_prlo_t *req;
11366 11365
11367 11366 req = (la_els_prlo_t *)buf->ub_buffer;
11368 11367
11369 11368 if ((ntohs(req->payload_length) !=
11370 11369 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11371 11370 (req->page_length != sizeof (service_parameter_page_t))) {
11372 11371 /*
11373 11372 * We are being very restrictive. Only on page per
11374 11373 * payload. If it is not the case we reject the ELS although
11375 11374 * we should reply indicating we handle only single page
11376 11375 * per PRLO.
11377 11376 */
11378 11377 goto fp_reject_prlo;
11379 11378 }
11380 11379
11381 11380 if (ntohs(req->payload_length) > buf->ub_bufsize) {
11382 11381 /*
11383 11382 * This is in case the payload advertizes a size bigger than
11384 11383 * what it really is.
11385 11384 */
11386 11385 goto fp_reject_prlo;
11387 11386 }
11388 11387
11389 11388 mutex_enter(&port->fp_mutex);
11390 11389 busy = port->fp_statec_busy;
11391 11390 mutex_exit(&port->fp_mutex);
11392 11391
11393 11392 mutex_enter(&pd->pd_mutex);
11394 11393 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11395 11394 if (!busy) {
11396 11395 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11397 11396 pd->pd_state == PORT_DEVICE_INVALID ||
11398 11397 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11399 11398 pd->pd_type == PORT_DEVICE_OLD) {
11400 11399 busy++;
11401 11400 }
11402 11401 }
11403 11402
11404 11403 if (busy) {
11405 11404 mutex_exit(&pd->pd_mutex);
11406 11405
11407 11406 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11408 11407 "pd=%p - busy",
11409 11408 pd->pd_port_id.port_id, pd);
11410 11409
11411 11410 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11412 11411 goto fp_reject_prlo;
11413 11412 }
11414 11413 } else {
11415 11414 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11416 11415
11417 11416 if (tolerance) {
11418 11417 fctl_tc_reset(&pd->pd_logo_tc);
11419 11418 retain = 0;
11420 11419 pd->pd_state = PORT_DEVICE_INVALID;
11421 11420 }
11422 11421
11423 11422 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11424 11423 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11425 11424 tolerance, retain);
11426 11425
11427 11426 pd->pd_aux_flags |= PD_LOGGED_OUT;
11428 11427 mutex_exit(&pd->pd_mutex);
11429 11428
11430 11429 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11431 11430 if (cmd == NULL) {
11432 11431 return;
11433 11432 }
11434 11433
11435 11434 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11436 11435 if (rval != FC_SUCCESS) {
11437 11436 fp_free_pkt(cmd);
11438 11437 return;
11439 11438 }
11440 11439
11441 11440 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11442 11441
11443 11442 if (retain) {
11444 11443 fp_unregister_login(pd);
11445 11444 fctl_copy_portmap(listptr, pd);
11446 11445 } else {
11447 11446 uint32_t d_id;
11448 11447 char ww_name[17];
11449 11448
11450 11449 mutex_enter(&pd->pd_mutex);
11451 11450 d_id = pd->pd_port_id.port_id;
11452 11451 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11453 11452 mutex_exit(&pd->pd_mutex);
11454 11453
11455 11454 FP_TRACE(FP_NHEAD2(9, 0),
11456 11455 "N_x Port with D_ID=%x, PWWN=%s logged out"
11457 11456 " %d times in %d us; Giving up", d_id, ww_name,
11458 11457 FC_LOGO_TOLERANCE_LIMIT,
11459 11458 FC_LOGO_TOLERANCE_TIME_LIMIT);
11460 11459
11461 11460 fp_fillout_old_map(listptr, pd, 0);
11462 11461 listptr->map_type = PORT_DEVICE_OLD;
11463 11462 }
11464 11463
11465 11464 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11466 11465 return;
11467 11466 }
11468 11467
11469 11468 fp_reject_prlo:
11470 11469
11471 11470 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11472 11471 if (cmd != NULL) {
11473 11472 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11474 11473 FC_REASON_INVALID_LINK_CTRL, job);
11475 11474
11476 11475 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11477 11476 fp_free_pkt(cmd);
11478 11477 }
11479 11478 }
11480 11479 }
11481 11480
11482 11481 /*
11483 11482 * Unsolicited LOGO handler
11484 11483 */
11485 11484 static void
11486 11485 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11487 11486 fc_remote_port_t *pd, job_request_t *job)
11488 11487 {
11489 11488 int busy;
11490 11489 int rval;
11491 11490 int retain;
11492 11491 fp_cmd_t *cmd;
11493 11492 fc_portmap_t *listptr;
11494 11493 boolean_t tolerance;
11495 11494
11496 11495 mutex_enter(&port->fp_mutex);
11497 11496 busy = port->fp_statec_busy;
11498 11497 mutex_exit(&port->fp_mutex);
11499 11498
11500 11499 mutex_enter(&pd->pd_mutex);
11501 11500 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11502 11501 if (!busy) {
11503 11502 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11504 11503 pd->pd_state == PORT_DEVICE_INVALID ||
11505 11504 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11506 11505 pd->pd_type == PORT_DEVICE_OLD) {
11507 11506 busy++;
11508 11507 }
11509 11508 }
11510 11509
11511 11510 if (busy) {
11512 11511 mutex_exit(&pd->pd_mutex);
11513 11512
11514 11513 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11515 11514 "pd=%p - busy",
11516 11515 pd->pd_port_id.port_id, pd);
11517 11516
11518 11517 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11519 11518 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11520 11519 0, KM_SLEEP, pd);
11521 11520 if (cmd != NULL) {
11522 11521 fp_els_rjt_init(port, cmd, buf,
11523 11522 FC_ACTION_NON_RETRYABLE,
11524 11523 FC_REASON_INVALID_LINK_CTRL, job);
11525 11524
11526 11525 if (fp_sendcmd(port, cmd,
11527 11526 port->fp_fca_handle) != FC_SUCCESS) {
11528 11527 fp_free_pkt(cmd);
11529 11528 }
11530 11529 }
11531 11530 }
11532 11531 } else {
11533 11532 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11534 11533
11535 11534 if (tolerance) {
11536 11535 fctl_tc_reset(&pd->pd_logo_tc);
11537 11536 retain = 0;
11538 11537 pd->pd_state = PORT_DEVICE_INVALID;
11539 11538 }
11540 11539
11541 11540 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11542 11541 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11543 11542 tolerance, retain);
11544 11543
11545 11544 pd->pd_aux_flags |= PD_LOGGED_OUT;
11546 11545 mutex_exit(&pd->pd_mutex);
11547 11546
11548 11547 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11549 11548 KM_SLEEP, pd);
11550 11549 if (cmd == NULL) {
11551 11550 return;
11552 11551 }
11553 11552
11554 11553 fp_els_acc_init(port, cmd, buf, job);
11555 11554
11556 11555 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11557 11556 if (rval != FC_SUCCESS) {
11558 11557 fp_free_pkt(cmd);
11559 11558 return;
11560 11559 }
11561 11560
11562 11561 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11563 11562
11564 11563 if (retain) {
11565 11564 job_request_t *job;
11566 11565 fctl_ns_req_t *ns_cmd;
11567 11566
11568 11567 /*
11569 11568 * when get LOGO, first try to get PID from nameserver
11570 11569 * if failed, then we do not need
11571 11570 * send PLOGI to that remote port
11572 11571 */
11573 11572 job = fctl_alloc_job(
11574 11573 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11575 11574
11576 11575 if (job != NULL) {
11577 11576 ns_cmd = fctl_alloc_ns_cmd(
11578 11577 sizeof (ns_req_gid_pn_t),
11579 11578 sizeof (ns_resp_gid_pn_t),
11580 11579 sizeof (ns_resp_gid_pn_t),
11581 11580 0, KM_SLEEP);
11582 11581 if (ns_cmd != NULL) {
11583 11582 int ret;
11584 11583 job->job_result = FC_SUCCESS;
11585 11584 ns_cmd->ns_cmd_code = NS_GID_PN;
11586 11585 ((ns_req_gid_pn_t *)
11587 11586 (ns_cmd->ns_cmd_buf))->pwwn =
11588 11587 pd->pd_port_name;
11589 11588 ret = fp_ns_query(
11590 11589 port, ns_cmd, job, 1, KM_SLEEP);
11591 11590 if ((ret != FC_SUCCESS) ||
11592 11591 (job->job_result != FC_SUCCESS)) {
11593 11592 fctl_free_ns_cmd(ns_cmd);
11594 11593 fctl_dealloc_job(job);
11595 11594 FP_TRACE(FP_NHEAD2(9, 0),
11596 11595 "NS query failed,",
11597 11596 " delete pd");
11598 11597 goto delete_pd;
11599 11598 }
11600 11599 fctl_free_ns_cmd(ns_cmd);
11601 11600 }
11602 11601 fctl_dealloc_job(job);
11603 11602 }
11604 11603 fp_unregister_login(pd);
11605 11604 fctl_copy_portmap(listptr, pd);
11606 11605 } else {
11607 11606 uint32_t d_id;
11608 11607 char ww_name[17];
11609 11608
11610 11609 delete_pd:
11611 11610 mutex_enter(&pd->pd_mutex);
11612 11611 d_id = pd->pd_port_id.port_id;
11613 11612 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11614 11613 mutex_exit(&pd->pd_mutex);
11615 11614
11616 11615 FP_TRACE(FP_NHEAD2(9, 0),
11617 11616 "N_x Port with D_ID=%x, PWWN=%s logged out"
11618 11617 " %d times in %d us; Giving up", d_id, ww_name,
11619 11618 FC_LOGO_TOLERANCE_LIMIT,
11620 11619 FC_LOGO_TOLERANCE_TIME_LIMIT);
11621 11620
11622 11621 fp_fillout_old_map(listptr, pd, 0);
11623 11622 listptr->map_type = PORT_DEVICE_OLD;
11624 11623 }
11625 11624
11626 11625 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11627 11626 }
11628 11627 }
11629 11628
11630 11629
11631 11630 /*
11632 11631 * Perform general purpose preparation of a response to an unsolicited request
11633 11632 */
11634 11633 static void
11635 11634 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11636 11635 uchar_t r_ctl, uchar_t type)
11637 11636 {
11638 11637 pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11639 11638 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11640 11639 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11641 11640 pkt->pkt_cmd_fhdr.type = type;
11642 11641 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11643 11642 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11644 11643 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl;
11645 11644 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11646 11645 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11647 11646 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11648 11647 pkt->pkt_cmd_fhdr.ro = 0;
11649 11648 pkt->pkt_cmd_fhdr.rsvd = 0;
11650 11649 pkt->pkt_comp = fp_unsol_intr;
11651 11650 pkt->pkt_timeout = FP_ELS_TIMEOUT;
11652 11651 pkt->pkt_ub_resp_token = (opaque_t)buf;
11653 11652 }
11654 11653
11655 11654 /*
11656 11655 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11657 11656 * early development days of public loop soc+ firmware, numerous problems
11658 11657 * were encountered (the details are undocumented and history now) which
11659 11658 * led to the birth of this function.
11660 11659 *
11661 11660 * If a pre-allocated unsolicited response packet is free, send out an
11662 11661 * immediate response, otherwise submit the request to the port thread
11663 11662 * to do the deferred processing.
11664 11663 */
11665 11664 static void
11666 11665 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11667 11666 {
11668 11667 int sent;
11669 11668 int f_port;
11670 11669 int do_acc;
11671 11670 fp_cmd_t *cmd;
11672 11671 la_els_logi_t *payload;
11673 11672 fc_remote_port_t *pd;
11674 11673 char dww_name[17];
11675 11674
11676 11675 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11677 11676
11678 11677 cmd = port->fp_els_resp_pkt;
11679 11678
11680 11679 mutex_enter(&port->fp_mutex);
11681 11680 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11682 11681 mutex_exit(&port->fp_mutex);
11683 11682
11684 11683 switch (buf->ub_buffer[0]) {
11685 11684 case LA_ELS_PLOGI: {
11686 11685 int small;
11687 11686
11688 11687 payload = (la_els_logi_t *)buf->ub_buffer;
11689 11688
11690 11689 f_port = FP_IS_F_PORT(payload->
11691 11690 common_service.cmn_features) ? 1 : 0;
11692 11691
11693 11692 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11694 11693 &payload->nport_ww_name);
11695 11694 pd = fctl_get_remote_port_by_pwwn(port,
11696 11695 &payload->nport_ww_name);
11697 11696 if (pd) {
11698 11697 mutex_enter(&pd->pd_mutex);
11699 11698 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11700 11699 /*
11701 11700 * Most likely this means a cross login is in
11702 11701 * progress or a device about to be yanked out.
11703 11702 * Only accept the plogi if my wwn is smaller.
11704 11703 */
11705 11704 if (pd->pd_type == PORT_DEVICE_OLD) {
11706 11705 sent = 1;
11707 11706 }
11708 11707 /*
11709 11708 * Stop plogi request (if any)
11710 11709 * attempt from local side to speedup
11711 11710 * the discovery progress.
11712 11711 * Mark the pd as PD_PLOGI_RECEPIENT.
11713 11712 */
11714 11713 if (f_port == 0 && small < 0) {
11715 11714 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11716 11715 }
11717 11716 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11718 11717
11719 11718 mutex_exit(&pd->pd_mutex);
11720 11719
11721 11720 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11722 11721 "Unsol PLOGI received. PD still exists in the "
11723 11722 "PWWN list. pd=%p PWWN=%s, sent=%x",
11724 11723 pd, dww_name, sent);
11725 11724
11726 11725 if (f_port == 0 && small < 0) {
11727 11726 FP_TRACE(FP_NHEAD1(3, 0),
11728 11727 "fp_i_handle_unsol_els: Mark the pd"
11729 11728 " as plogi recipient, pd=%p, PWWN=%s"
11730 11729 ", sent=%x",
11731 11730 pd, dww_name, sent);
11732 11731 }
11733 11732 } else {
11734 11733 sent = 0;
11735 11734 }
11736 11735
11737 11736 /*
11738 11737 * To avoid Login collisions, accept only if my WWN
11739 11738 * is smaller than the requester (A curious side note
11740 11739 * would be that this rule may not satisfy the PLOGIs
11741 11740 * initiated by the switch from not-so-well known
11742 11741 * ports such as 0xFFFC41)
11743 11742 */
11744 11743 if ((f_port == 0 && small < 0) ||
11745 11744 (((small > 0 && do_acc) ||
11746 11745 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11747 11746 if (fp_is_class_supported(port->fp_cos,
11748 11747 buf->ub_class) == FC_FAILURE) {
11749 11748 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11750 11749 cmd->cmd_pkt.pkt_cmdlen =
11751 11750 sizeof (la_els_rjt_t);
11752 11751 cmd->cmd_pkt.pkt_rsplen = 0;
11753 11752 fp_els_rjt_init(port, cmd, buf,
11754 11753 FC_ACTION_NON_RETRYABLE,
11755 11754 FC_REASON_CLASS_NOT_SUPP, NULL);
11756 11755 FP_TRACE(FP_NHEAD1(3, 0),
11757 11756 "fp_i_handle_unsol_els: "
11758 11757 "Unsupported class. "
11759 11758 "Rejecting PLOGI");
11760 11759
11761 11760 } else {
11762 11761 mutex_enter(&port->fp_mutex);
11763 11762 port->fp_els_resp_pkt_busy = 0;
11764 11763 mutex_exit(&port->fp_mutex);
11765 11764 return;
11766 11765 }
11767 11766 } else {
11768 11767 cmd->cmd_pkt.pkt_cmdlen =
11769 11768 sizeof (la_els_logi_t);
11770 11769 cmd->cmd_pkt.pkt_rsplen = 0;
11771 11770
11772 11771 /*
11773 11772 * If fp_port_id is zero and topology is
11774 11773 * Point-to-Point, get the local port id from
11775 11774 * the d_id in the PLOGI request.
11776 11775 * If the outgoing FLOGI hasn't been accepted,
11777 11776 * the topology will be unknown here. But it's
11778 11777 * still safe to save the d_id to fp_port_id,
11779 11778 * just because it will be overwritten later
11780 11779 * if the topology is not Point-to-Point.
11781 11780 */
11782 11781 mutex_enter(&port->fp_mutex);
11783 11782 if ((port->fp_port_id.port_id == 0) &&
11784 11783 (port->fp_topology == FC_TOP_PT_PT ||
11785 11784 port->fp_topology == FC_TOP_UNKNOWN)) {
11786 11785 port->fp_port_id.port_id =
11787 11786 buf->ub_frame.d_id;
11788 11787 }
11789 11788 mutex_exit(&port->fp_mutex);
11790 11789
11791 11790 /*
11792 11791 * Sometime later, we should validate
11793 11792 * the service parameters instead of
11794 11793 * just accepting it.
11795 11794 */
11796 11795 fp_login_acc_init(port, cmd, buf, NULL,
11797 11796 KM_NOSLEEP);
11798 11797 FP_TRACE(FP_NHEAD1(3, 0),
11799 11798 "fp_i_handle_unsol_els: Accepting PLOGI,"
11800 11799 " f_port=%d, small=%d, do_acc=%d,"
11801 11800 " sent=%d.", f_port, small, do_acc,
11802 11801 sent);
11803 11802 }
11804 11803 } else {
11805 11804 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11806 11805 port->fp_options & FP_SEND_RJT) {
11807 11806 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11808 11807 cmd->cmd_pkt.pkt_rsplen = 0;
11809 11808 fp_els_rjt_init(port, cmd, buf,
11810 11809 FC_ACTION_NON_RETRYABLE,
11811 11810 FC_REASON_LOGICAL_BSY, NULL);
11812 11811 FP_TRACE(FP_NHEAD1(3, 0),
11813 11812 "fp_i_handle_unsol_els: "
11814 11813 "Rejecting PLOGI with Logical Busy."
11815 11814 "Possible Login collision.");
11816 11815 } else {
11817 11816 mutex_enter(&port->fp_mutex);
11818 11817 port->fp_els_resp_pkt_busy = 0;
11819 11818 mutex_exit(&port->fp_mutex);
11820 11819 return;
11821 11820 }
11822 11821 }
11823 11822 break;
11824 11823 }
11825 11824
11826 11825 case LA_ELS_FLOGI:
11827 11826 if (fp_is_class_supported(port->fp_cos,
11828 11827 buf->ub_class) == FC_FAILURE) {
11829 11828 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11830 11829 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11831 11830 cmd->cmd_pkt.pkt_rsplen = 0;
11832 11831 fp_els_rjt_init(port, cmd, buf,
11833 11832 FC_ACTION_NON_RETRYABLE,
11834 11833 FC_REASON_CLASS_NOT_SUPP, NULL);
11835 11834 FP_TRACE(FP_NHEAD1(3, 0),
11836 11835 "fp_i_handle_unsol_els: "
11837 11836 "Unsupported Class. Rejecting FLOGI.");
11838 11837 } else {
11839 11838 mutex_enter(&port->fp_mutex);
11840 11839 port->fp_els_resp_pkt_busy = 0;
11841 11840 mutex_exit(&port->fp_mutex);
11842 11841 return;
11843 11842 }
11844 11843 } else {
11845 11844 mutex_enter(&port->fp_mutex);
11846 11845 if (FC_PORT_STATE_MASK(port->fp_state) !=
11847 11846 FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11848 11847 buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11849 11848 mutex_exit(&port->fp_mutex);
11850 11849 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11851 11850 cmd->cmd_pkt.pkt_cmdlen =
11852 11851 sizeof (la_els_rjt_t);
11853 11852 cmd->cmd_pkt.pkt_rsplen = 0;
11854 11853 fp_els_rjt_init(port, cmd, buf,
11855 11854 FC_ACTION_NON_RETRYABLE,
11856 11855 FC_REASON_INVALID_LINK_CTRL,
11857 11856 NULL);
11858 11857 FP_TRACE(FP_NHEAD1(3, 0),
11859 11858 "fp_i_handle_unsol_els: "
11860 11859 "Invalid Link Ctrl. "
11861 11860 "Rejecting FLOGI.");
11862 11861 } else {
11863 11862 mutex_enter(&port->fp_mutex);
11864 11863 port->fp_els_resp_pkt_busy = 0;
11865 11864 mutex_exit(&port->fp_mutex);
11866 11865 return;
11867 11866 }
11868 11867 } else {
11869 11868 mutex_exit(&port->fp_mutex);
11870 11869 cmd->cmd_pkt.pkt_cmdlen =
11871 11870 sizeof (la_els_logi_t);
11872 11871 cmd->cmd_pkt.pkt_rsplen = 0;
11873 11872 /*
11874 11873 * Let's not aggressively validate the N_Port's
11875 11874 * service parameters until PLOGI. Suffice it
11876 11875 * to give a hint that we are an N_Port and we
11877 11876 * are game to some serious stuff here.
11878 11877 */
11879 11878 fp_login_acc_init(port, cmd, buf,
11880 11879 NULL, KM_NOSLEEP);
11881 11880 FP_TRACE(FP_NHEAD1(3, 0),
11882 11881 "fp_i_handle_unsol_els: "
11883 11882 "Accepting FLOGI.");
11884 11883 }
11885 11884 }
11886 11885 break;
11887 11886
11888 11887 default:
11889 11888 return;
11890 11889 }
11891 11890
11892 11891 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11893 11892 mutex_enter(&port->fp_mutex);
11894 11893 port->fp_els_resp_pkt_busy = 0;
11895 11894 mutex_exit(&port->fp_mutex);
11896 11895 }
11897 11896 }
11898 11897
11899 11898
11900 11899 /*
11901 11900 * Handle unsolicited PLOGI request
11902 11901 */
11903 11902 static void
11904 11903 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11905 11904 job_request_t *job, int sleep)
11906 11905 {
11907 11906 int sent;
11908 11907 int small;
11909 11908 int f_port;
11910 11909 int do_acc;
11911 11910 fp_cmd_t *cmd;
11912 11911 la_wwn_t *swwn;
11913 11912 la_wwn_t *dwwn;
11914 11913 la_els_logi_t *payload;
11915 11914 fc_remote_port_t *pd;
11916 11915 char dww_name[17];
11917 11916
11918 11917 payload = (la_els_logi_t *)buf->ub_buffer;
11919 11918 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11920 11919
11921 11920 mutex_enter(&port->fp_mutex);
11922 11921 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11923 11922 mutex_exit(&port->fp_mutex);
11924 11923
11925 11924 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11926 11925 "type=%x, f_ctl=%x"
11927 11926 " seq_id=%x, ox_id=%x, rx_id=%x"
11928 11927 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11929 11928 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11930 11929 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11931 11930
11932 11931 swwn = &port->fp_service_params.nport_ww_name;
11933 11932 dwwn = &payload->nport_ww_name;
11934 11933 small = fctl_wwn_cmp(swwn, dwwn);
11935 11934 pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11936 11935 if (pd) {
11937 11936 mutex_enter(&pd->pd_mutex);
11938 11937 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11939 11938 /*
11940 11939 * Most likely this means a cross login is in
11941 11940 * progress or a device about to be yanked out.
11942 11941 * Only accept the plogi if my wwn is smaller.
11943 11942 */
11944 11943
11945 11944 if (pd->pd_type == PORT_DEVICE_OLD) {
11946 11945 sent = 1;
11947 11946 }
11948 11947 /*
11949 11948 * Stop plogi request (if any)
11950 11949 * attempt from local side to speedup
11951 11950 * the discovery progress.
11952 11951 * Mark the pd as PD_PLOGI_RECEPIENT.
11953 11952 */
11954 11953 if (f_port == 0 && small < 0) {
11955 11954 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11956 11955 }
11957 11956 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11958 11957
11959 11958 mutex_exit(&pd->pd_mutex);
11960 11959
11961 11960 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11962 11961 " received. PD still exists in the PWWN list. pd=%p "
11963 11962 "PWWN=%s, sent=%x", pd, dww_name, sent);
11964 11963
11965 11964 if (f_port == 0 && small < 0) {
11966 11965 FP_TRACE(FP_NHEAD1(3, 0),
11967 11966 "fp_handle_unsol_plogi: Mark the pd"
11968 11967 " as plogi recipient, pd=%p, PWWN=%s"
11969 11968 ", sent=%x",
11970 11969 pd, dww_name, sent);
11971 11970 }
11972 11971 } else {
11973 11972 sent = 0;
11974 11973 }
11975 11974
11976 11975 /*
11977 11976 * Avoid Login collisions by accepting only if my WWN is smaller.
11978 11977 *
11979 11978 * A side note: There is no need to start a PLOGI from this end in
11980 11979 * this context if login isn't going to be accepted for the
11981 11980 * above reason as either a LIP (in private loop), RSCN (in
11982 11981 * fabric topology), or an FLOGI (in point to point - Huh ?
11983 11982 * check FC-PH) would normally drive the PLOGI from this end.
11984 11983 * At this point of time there is no need for an inbound PLOGI
11985 11984 * to kick an outbound PLOGI when it is going to be rejected
11986 11985 * for the reason of WWN being smaller. However it isn't hard
11987 11986 * to do that either (when such a need arises, start a timer
11988 11987 * for a duration that extends beyond a normal device discovery
11989 11988 * time and check if an outbound PLOGI did go before that, if
11990 11989 * none fire one)
11991 11990 *
11992 11991 * Unfortunately, as it turned out, during booting, it is possible
11993 11992 * to miss another initiator in the same loop as port driver
11994 11993 * instances are serially attached. While preserving the above
11995 11994 * comments for belly laughs, please kick an outbound PLOGI in
11996 11995 * a non-switch environment (which is a pt pt between N_Ports or
11997 11996 * a private loop)
11998 11997 *
11999 11998 * While preserving the above comments for amusement, send an
12000 11999 * ACC if the PLOGI is going to be rejected for WWN being smaller
12001 12000 * when no discovery is in progress at this end. Turn around
12002 12001 * and make the port device as the PLOGI initiator, so that
12003 12002 * during subsequent link/loop initialization, this end drives
12004 12003 * the PLOGI (In fact both ends do in this particular case, but
12005 12004 * only one wins)
12006 12005 *
12007 12006 * Make sure the PLOGIs initiated by the switch from not-so-well-known
12008 12007 * ports (such as 0xFFFC41) are accepted too.
12009 12008 */
12010 12009 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
12011 12010 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
12012 12011 if (fp_is_class_supported(port->fp_cos,
12013 12012 buf->ub_class) == FC_FAILURE) {
12014 12013 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12015 12014 cmd = fp_alloc_pkt(port,
12016 12015 sizeof (la_els_logi_t), 0, sleep, pd);
12017 12016 if (cmd == NULL) {
12018 12017 return;
12019 12018 }
12020 12019 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12021 12020 cmd->cmd_pkt.pkt_rsplen = 0;
12022 12021 fp_els_rjt_init(port, cmd, buf,
12023 12022 FC_ACTION_NON_RETRYABLE,
12024 12023 FC_REASON_CLASS_NOT_SUPP, job);
12025 12024 FP_TRACE(FP_NHEAD1(3, 0),
12026 12025 "fp_handle_unsol_plogi: "
12027 12026 "Unsupported class. rejecting PLOGI");
12028 12027 }
12029 12028 } else {
12030 12029 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12031 12030 0, sleep, pd);
12032 12031 if (cmd == NULL) {
12033 12032 return;
12034 12033 }
12035 12034 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
12036 12035 cmd->cmd_pkt.pkt_rsplen = 0;
12037 12036
12038 12037 /*
12039 12038 * Sometime later, we should validate the service
12040 12039 * parameters instead of just accepting it.
12041 12040 */
12042 12041 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12043 12042 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12044 12043 "Accepting PLOGI, f_port=%d, small=%d, "
12045 12044 "do_acc=%d, sent=%d.", f_port, small, do_acc,
12046 12045 sent);
12047 12046
12048 12047 /*
12049 12048 * If fp_port_id is zero and topology is
12050 12049 * Point-to-Point, get the local port id from
12051 12050 * the d_id in the PLOGI request.
12052 12051 * If the outgoing FLOGI hasn't been accepted,
12053 12052 * the topology will be unknown here. But it's
12054 12053 * still safe to save the d_id to fp_port_id,
12055 12054 * just because it will be overwritten later
12056 12055 * if the topology is not Point-to-Point.
12057 12056 */
12058 12057 mutex_enter(&port->fp_mutex);
12059 12058 if ((port->fp_port_id.port_id == 0) &&
12060 12059 (port->fp_topology == FC_TOP_PT_PT ||
12061 12060 port->fp_topology == FC_TOP_UNKNOWN)) {
12062 12061 port->fp_port_id.port_id =
12063 12062 buf->ub_frame.d_id;
12064 12063 }
12065 12064 mutex_exit(&port->fp_mutex);
12066 12065 }
12067 12066 } else {
12068 12067 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12069 12068 port->fp_options & FP_SEND_RJT) {
12070 12069 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12071 12070 0, sleep, pd);
12072 12071 if (cmd == NULL) {
12073 12072 return;
12074 12073 }
12075 12074 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12076 12075 cmd->cmd_pkt.pkt_rsplen = 0;
12077 12076 /*
12078 12077 * Send out Logical busy to indicate
12079 12078 * the detection of PLOGI collision
12080 12079 */
12081 12080 fp_els_rjt_init(port, cmd, buf,
12082 12081 FC_ACTION_NON_RETRYABLE,
12083 12082 FC_REASON_LOGICAL_BSY, job);
12084 12083
12085 12084 fc_wwn_to_str(dwwn, dww_name);
12086 12085 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12087 12086 "Rejecting Unsol PLOGI with Logical Busy."
12088 12087 "possible PLOGI collision. PWWN=%s, sent=%x",
12089 12088 dww_name, sent);
12090 12089 } else {
12091 12090 return;
12092 12091 }
12093 12092 }
12094 12093
12095 12094 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12096 12095 fp_free_pkt(cmd);
12097 12096 }
12098 12097 }
12099 12098
12100 12099
12101 12100 /*
12102 12101 * Handle mischievous turning over of our own FLOGI requests back to
12103 12102 * us by the SOC+ microcode. In other words, look at the class of such
12104 12103 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12105 12104 * on the floor
12106 12105 */
12107 12106 static void
12108 12107 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12109 12108 job_request_t *job, int sleep)
12110 12109 {
12111 12110 uint32_t state;
12112 12111 uint32_t s_id;
12113 12112 fp_cmd_t *cmd;
12114 12113
12115 12114 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12116 12115 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12117 12116 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12118 12117 0, sleep, NULL);
12119 12118 if (cmd == NULL) {
12120 12119 return;
12121 12120 }
12122 12121 fp_els_rjt_init(port, cmd, buf,
12123 12122 FC_ACTION_NON_RETRYABLE,
12124 12123 FC_REASON_CLASS_NOT_SUPP, job);
12125 12124 } else {
12126 12125 return;
12127 12126 }
12128 12127 } else {
12129 12128
12130 12129 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12131 12130 " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12132 12131 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12133 12132 buf->ub_frame.s_id, buf->ub_frame.d_id,
12134 12133 buf->ub_frame.type, buf->ub_frame.f_ctl,
12135 12134 buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12136 12135 buf->ub_frame.rx_id, buf->ub_frame.ro);
12137 12136
12138 12137 mutex_enter(&port->fp_mutex);
12139 12138 state = FC_PORT_STATE_MASK(port->fp_state);
12140 12139 s_id = port->fp_port_id.port_id;
12141 12140 mutex_exit(&port->fp_mutex);
12142 12141
12143 12142 if (state != FC_STATE_ONLINE ||
12144 12143 (s_id && buf->ub_frame.s_id == s_id)) {
12145 12144 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12146 12145 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12147 12146 0, sleep, NULL);
12148 12147 if (cmd == NULL) {
12149 12148 return;
12150 12149 }
12151 12150 fp_els_rjt_init(port, cmd, buf,
12152 12151 FC_ACTION_NON_RETRYABLE,
12153 12152 FC_REASON_INVALID_LINK_CTRL, job);
12154 12153 FP_TRACE(FP_NHEAD1(3, 0),
12155 12154 "fp_handle_unsol_flogi: "
12156 12155 "Rejecting PLOGI. Invalid Link CTRL");
12157 12156 } else {
12158 12157 return;
12159 12158 }
12160 12159 } else {
12161 12160 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12162 12161 0, sleep, NULL);
12163 12162 if (cmd == NULL) {
12164 12163 return;
12165 12164 }
12166 12165 /*
12167 12166 * Let's not aggressively validate the N_Port's
12168 12167 * service parameters until PLOGI. Suffice it
12169 12168 * to give a hint that we are an N_Port and we
12170 12169 * are game to some serious stuff here.
12171 12170 */
12172 12171 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12173 12172 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12174 12173 "Accepting PLOGI");
12175 12174 }
12176 12175 }
12177 12176
12178 12177 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12179 12178 fp_free_pkt(cmd);
12180 12179 }
12181 12180 }
12182 12181
12183 12182
12184 12183 /*
12185 12184 * Perform PLOGI accept
12186 12185 */
12187 12186 static void
12188 12187 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12189 12188 job_request_t *job, int sleep)
12190 12189 {
12191 12190 fc_packet_t *pkt;
12192 12191 fc_portmap_t *listptr;
12193 12192 la_els_logi_t payload;
12194 12193
12195 12194 ASSERT(buf != NULL);
12196 12195
12197 12196 /*
12198 12197 * If we are sending ACC to PLOGI and we haven't already
12199 12198 * create port and node device handles, let's create them
12200 12199 * here.
12201 12200 */
12202 12201 if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12203 12202 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12204 12203 int small;
12205 12204 int do_acc;
12206 12205 fc_remote_port_t *pd;
12207 12206 la_els_logi_t *req;
12208 12207
12209 12208 req = (la_els_logi_t *)buf->ub_buffer;
12210 12209 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12211 12210 &req->nport_ww_name);
12212 12211
12213 12212 mutex_enter(&port->fp_mutex);
12214 12213 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12215 12214 mutex_exit(&port->fp_mutex);
12216 12215
12217 12216 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12218 12217 port->fp_port_id.port_id, buf->ub_frame.s_id);
12219 12218 pd = fctl_create_remote_port(port, &req->node_ww_name,
12220 12219 &req->nport_ww_name, buf->ub_frame.s_id,
12221 12220 PD_PLOGI_RECEPIENT, sleep);
12222 12221 if (pd == NULL) {
12223 12222 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12224 12223 "Couldn't create port device for d_id:0x%x",
12225 12224 buf->ub_frame.s_id);
12226 12225
12227 12226 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12228 12227 "couldn't create port device d_id=%x",
12229 12228 buf->ub_frame.s_id);
12230 12229 } else {
12231 12230 /*
12232 12231 * usoc currently returns PLOGIs inline and
12233 12232 * the maximum buffer size is 60 bytes or so.
12234 12233 * So attempt not to look beyond what is in
12235 12234 * the unsolicited buffer
12236 12235 *
12237 12236 * JNI also traverses this path sometimes
12238 12237 */
12239 12238 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12240 12239 fp_register_login(NULL, pd, req, buf->ub_class);
12241 12240 } else {
12242 12241 mutex_enter(&pd->pd_mutex);
12243 12242 if (pd->pd_login_count == 0) {
12244 12243 pd->pd_login_count++;
12245 12244 }
12246 12245 pd->pd_state = PORT_DEVICE_LOGGED_IN;
12247 12246 pd->pd_login_class = buf->ub_class;
12248 12247 mutex_exit(&pd->pd_mutex);
12249 12248 }
12250 12249
12251 12250 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12252 12251 if (listptr != NULL) {
12253 12252 fctl_copy_portmap(listptr, pd);
12254 12253 (void) fp_ulp_devc_cb(port, listptr,
12255 12254 1, 1, sleep, 0);
12256 12255 }
12257 12256
12258 12257 if (small > 0 && do_acc) {
12259 12258 mutex_enter(&pd->pd_mutex);
12260 12259 pd->pd_recepient = PD_PLOGI_INITIATOR;
12261 12260 mutex_exit(&pd->pd_mutex);
12262 12261 }
12263 12262 }
12264 12263 }
12265 12264
12266 12265 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12267 12266 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12268 12267 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12269 12268 cmd->cmd_retry_count = 1;
12270 12269 cmd->cmd_ulp_pkt = NULL;
12271 12270
12272 12271 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12273 12272 cmd->cmd_job = job;
12274 12273
12275 12274 pkt = &cmd->cmd_pkt;
12276 12275
12277 12276 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12278 12277
12279 12278 payload = port->fp_service_params;
12280 12279 payload.ls_code.ls_code = LA_ELS_ACC;
12281 12280
12282 12281 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12283 12282 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12284 12283
12285 12284 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12286 12285 "bufsize:0x%x sizeof (la_els_logi):0x%x "
12287 12286 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12288 12287 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12289 12288 buf->ub_bufsize, sizeof (la_els_logi_t),
12290 12289 port->fp_service_params.nport_ww_name.w.naa_id,
12291 12290 port->fp_service_params.nport_ww_name.w.nport_id,
12292 12291 port->fp_service_params.nport_ww_name.w.wwn_hi,
12293 12292 port->fp_service_params.nport_ww_name.w.wwn_lo,
12294 12293 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12295 12294 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12296 12295 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12297 12296 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12298 12297 port->fp_statec_busy);
12299 12298 }
12300 12299
12301 12300
12302 12301 #define RSCN_EVENT_NAME_LEN 256
12303 12302
12304 12303 /*
12305 12304 * Handle RSCNs
12306 12305 */
12307 12306 static void
12308 12307 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12309 12308 job_request_t *job, int sleep)
12310 12309 {
12311 12310 uint32_t mask;
12312 12311 fp_cmd_t *cmd;
12313 12312 uint32_t count;
12314 12313 int listindex;
12315 12314 int16_t len;
12316 12315 fc_rscn_t *payload;
12317 12316 fc_portmap_t *listptr;
12318 12317 fctl_ns_req_t *ns_cmd;
12319 12318 fc_affected_id_t *page;
12320 12319 caddr_t nvname;
12321 12320 nvlist_t *attr_list = NULL;
12322 12321
12323 12322 mutex_enter(&port->fp_mutex);
12324 12323 if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12325 12324 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12326 12325 --port->fp_rscn_count;
12327 12326 }
12328 12327 mutex_exit(&port->fp_mutex);
12329 12328 return;
12330 12329 }
12331 12330 mutex_exit(&port->fp_mutex);
12332 12331
12333 12332 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12334 12333 if (cmd != NULL) {
12335 12334 fp_els_acc_init(port, cmd, buf, job);
12336 12335 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12337 12336 fp_free_pkt(cmd);
12338 12337 }
12339 12338 }
12340 12339
12341 12340 payload = (fc_rscn_t *)buf->ub_buffer;
12342 12341 ASSERT(payload->rscn_code == LA_ELS_RSCN);
12343 12342 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12344 12343
12345 12344 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12346 12345
12347 12346 if (len <= 0) {
12348 12347 mutex_enter(&port->fp_mutex);
12349 12348 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12350 12349 --port->fp_rscn_count;
12351 12350 }
12352 12351 mutex_exit(&port->fp_mutex);
12353 12352
12354 12353 return;
12355 12354 }
12356 12355
12357 12356 ASSERT((len & 0x3) == 0); /* Must be power of 4 */
12358 12357 count = (len >> 2) << 1; /* number of pages multiplied by 2 */
12359 12358
12360 12359 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12361 12360 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12362 12361
12363 12362 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12364 12363
12365 12364 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12366 12365 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12367 12366 0, sleep);
12368 12367 if (ns_cmd == NULL) {
12369 12368 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12370 12369
12371 12370 mutex_enter(&port->fp_mutex);
12372 12371 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12373 12372 --port->fp_rscn_count;
12374 12373 }
12375 12374 mutex_exit(&port->fp_mutex);
12376 12375
12377 12376 return;
12378 12377 }
12379 12378
12380 12379 ns_cmd->ns_cmd_code = NS_GPN_ID;
12381 12380
12382 12381 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12383 12382 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12384 12383 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12385 12384 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12386 12385 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12387 12386
12388 12387 /* Only proceed if we can allocate nvname and the nvlist */
12389 12388 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12390 12389 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12391 12390 KM_NOSLEEP) == DDI_SUCCESS) {
12392 12391 if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12393 12392 port->fp_instance) == DDI_SUCCESS &&
12394 12393 nvlist_add_byte_array(attr_list, "port-wwn",
12395 12394 port->fp_service_params.nport_ww_name.raw_wwn,
12396 12395 sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12397 12396 nvlist_free(attr_list);
12398 12397 attr_list = NULL;
12399 12398 }
12400 12399 }
12401 12400
12402 12401 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12403 12402 /* Add affected page to the event payload */
12404 12403 if (attr_list != NULL) {
12405 12404 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12406 12405 "affected_page_%d", listindex);
12407 12406 if (attr_list && nvlist_add_uint32(attr_list, nvname,
12408 12407 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12409 12408 /* We don't send a partial event, so dump it */
12410 12409 nvlist_free(attr_list);
12411 12410 attr_list = NULL;
12412 12411 }
12413 12412 }
12414 12413 /*
12415 12414 * Query the NS to get the Port WWN for this
12416 12415 * affected D_ID.
12417 12416 */
12418 12417 mask = 0;
12419 12418 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12420 12419 case FC_RSCN_PORT_ADDRESS:
12421 12420 fp_validate_rscn_page(port, page, job, ns_cmd,
12422 12421 listptr, &listindex, sleep);
12423 12422
12424 12423 if (listindex == 0) {
12425 12424 /*
12426 12425 * We essentially did not process this RSCN. So,
12427 12426 * ULPs are not going to be called and so we
12428 12427 * decrement the rscn_count
12429 12428 */
12430 12429 mutex_enter(&port->fp_mutex);
12431 12430 if (--port->fp_rscn_count ==
12432 12431 FC_INVALID_RSCN_COUNT) {
12433 12432 --port->fp_rscn_count;
12434 12433 }
12435 12434 mutex_exit(&port->fp_mutex);
12436 12435 }
12437 12436 break;
12438 12437
12439 12438 case FC_RSCN_AREA_ADDRESS:
12440 12439 mask = 0xFFFF00;
12441 12440 /* FALLTHROUGH */
12442 12441
12443 12442 case FC_RSCN_DOMAIN_ADDRESS:
12444 12443 if (!mask) {
12445 12444 mask = 0xFF0000;
12446 12445 }
12447 12446 fp_validate_area_domain(port, page->aff_d_id, mask,
12448 12447 job, sleep);
12449 12448 break;
12450 12449
12451 12450 case FC_RSCN_FABRIC_ADDRESS:
12452 12451 /*
12453 12452 * We need to discover all the devices on this
12454 12453 * port.
12455 12454 */
12456 12455 fp_validate_area_domain(port, 0, 0, job, sleep);
12457 12456 break;
12458 12457
12459 12458 default:
12460 12459 break;
12461 12460 }
12462 12461 }
12463 12462 if (attr_list != NULL) {
12464 12463 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12465 12464 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12466 12465 NULL, DDI_SLEEP);
12467 12466 nvlist_free(attr_list);
12468 12467 } else {
12469 12468 FP_TRACE(FP_NHEAD1(9, 0),
12470 12469 "RSCN handled, but event not sent to userland");
12471 12470 }
12472 12471 if (nvname != NULL) {
12473 12472 kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12474 12473 }
12475 12474
12476 12475 if (ns_cmd) {
12477 12476 fctl_free_ns_cmd(ns_cmd);
12478 12477 }
12479 12478
12480 12479 if (listindex) {
12481 12480 #ifdef DEBUG
12482 12481 page = (fc_affected_id_t *)(buf->ub_buffer +
12483 12482 sizeof (fc_rscn_t));
12484 12483
12485 12484 if (listptr->map_did.port_id != page->aff_d_id) {
12486 12485 FP_TRACE(FP_NHEAD1(9, 0),
12487 12486 "PORT RSCN: processed=%x, reporting=%x",
12488 12487 listptr->map_did.port_id, page->aff_d_id);
12489 12488 }
12490 12489 #endif
12491 12490
12492 12491 (void) fp_ulp_devc_cb(port, listptr, listindex, count,
12493 12492 sleep, 0);
12494 12493 } else {
12495 12494 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12496 12495 }
12497 12496 }
12498 12497
12499 12498
12500 12499 /*
12501 12500 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12502 12501 */
12503 12502 static void
12504 12503 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12505 12504 {
12506 12505 int is_switch;
12507 12506 int initiator;
12508 12507 fc_local_port_t *port;
12509 12508
12510 12509 port = pd->pd_port;
12511 12510
12512 12511 /* This function has the following bunch of assumptions */
12513 12512 ASSERT(port != NULL);
12514 12513 ASSERT(MUTEX_HELD(&port->fp_mutex));
12515 12514 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12516 12515 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12517 12516
12518 12517 pd->pd_state = PORT_DEVICE_INVALID;
12519 12518 pd->pd_type = PORT_DEVICE_OLD;
12520 12519 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12521 12520 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12522 12521
12523 12522 fctl_delist_did_table(port, pd);
12524 12523 fctl_delist_pwwn_table(port, pd);
12525 12524
12526 12525 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12527 12526 " removed the PD=%p from DID and PWWN tables",
12528 12527 port, pd->pd_port_id.port_id, pd);
12529 12528
12530 12529 if ((!flag) && port && initiator && is_switch) {
12531 12530 (void) fctl_add_orphan_held(port, pd);
12532 12531 }
12533 12532 fctl_copy_portmap_held(map, pd);
12534 12533 map->map_pd = pd;
12535 12534 }
12536 12535
12537 12536 /*
12538 12537 * Fill out old map for ULPs
12539 12538 */
12540 12539 static void
12541 12540 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12542 12541 {
12543 12542 int is_switch;
12544 12543 int initiator;
12545 12544 fc_local_port_t *port;
12546 12545
12547 12546 mutex_enter(&pd->pd_mutex);
12548 12547 port = pd->pd_port;
12549 12548 mutex_exit(&pd->pd_mutex);
12550 12549
12551 12550 mutex_enter(&port->fp_mutex);
12552 12551 mutex_enter(&pd->pd_mutex);
12553 12552
12554 12553 pd->pd_state = PORT_DEVICE_INVALID;
12555 12554 pd->pd_type = PORT_DEVICE_OLD;
12556 12555 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12557 12556 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12558 12557
12559 12558 fctl_delist_did_table(port, pd);
12560 12559 fctl_delist_pwwn_table(port, pd);
12561 12560
12562 12561 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12563 12562 " removed the PD=%p from DID and PWWN tables",
12564 12563 port, pd->pd_port_id.port_id, pd);
12565 12564
12566 12565 mutex_exit(&pd->pd_mutex);
12567 12566 mutex_exit(&port->fp_mutex);
12568 12567
12569 12568 ASSERT(port != NULL);
12570 12569 if ((!flag) && port && initiator && is_switch) {
12571 12570 (void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12572 12571 }
12573 12572 fctl_copy_portmap(map, pd);
12574 12573 map->map_pd = pd;
12575 12574 }
12576 12575
12577 12576
12578 12577 /*
12579 12578 * Fillout Changed Map for ULPs
12580 12579 */
12581 12580 static void
12582 12581 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12583 12582 uint32_t *new_did, la_wwn_t *new_pwwn)
12584 12583 {
12585 12584 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12586 12585
12587 12586 pd->pd_type = PORT_DEVICE_CHANGED;
12588 12587 if (new_did) {
12589 12588 pd->pd_port_id.port_id = *new_did;
12590 12589 }
12591 12590 if (new_pwwn) {
12592 12591 pd->pd_port_name = *new_pwwn;
12593 12592 }
12594 12593 mutex_exit(&pd->pd_mutex);
12595 12594
12596 12595 fctl_copy_portmap(map, pd);
12597 12596
12598 12597 mutex_enter(&pd->pd_mutex);
12599 12598 pd->pd_type = PORT_DEVICE_NOCHANGE;
12600 12599 }
12601 12600
12602 12601
12603 12602 /*
12604 12603 * Fillout New Name Server map
12605 12604 */
12606 12605 static void
12607 12606 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12608 12607 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12609 12608 {
12610 12609 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12611 12610
12612 12611 if (handle) {
12613 12612 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12614 12613 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12615 12614 DDI_DEV_AUTOINCR);
12616 12615 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12617 12616 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12618 12617 DDI_DEV_AUTOINCR);
12619 12618 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12620 12619 (uint8_t *)gan_resp->gan_fc4types,
12621 12620 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12622 12621 } else {
12623 12622 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12624 12623 sizeof (gan_resp->gan_pwwn));
12625 12624 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12626 12625 sizeof (gan_resp->gan_nwwn));
12627 12626 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12628 12627 sizeof (gan_resp->gan_fc4types));
12629 12628 }
12630 12629 port_map->map_did.port_id = d_id;
12631 12630 port_map->map_did.priv_lilp_posit = 0;
12632 12631 port_map->map_hard_addr.hard_addr = 0;
12633 12632 port_map->map_hard_addr.rsvd = 0;
12634 12633 port_map->map_state = PORT_DEVICE_INVALID;
12635 12634 port_map->map_type = PORT_DEVICE_NEW;
12636 12635 port_map->map_flags = 0;
12637 12636 port_map->map_pd = NULL;
12638 12637
12639 12638 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12640 12639
12641 12640 ASSERT(port != NULL);
12642 12641 }
12643 12642
12644 12643
12645 12644 /*
12646 12645 * Perform LINIT ELS
12647 12646 */
12648 12647 static int
12649 12648 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12650 12649 job_request_t *job)
12651 12650 {
12652 12651 int rval;
12653 12652 uint32_t d_id;
12654 12653 uint32_t s_id;
12655 12654 uint32_t lfa;
12656 12655 uchar_t class;
12657 12656 uint32_t ret;
12658 12657 fp_cmd_t *cmd;
12659 12658 fc_porttype_t ptype;
12660 12659 fc_packet_t *pkt;
12661 12660 fc_linit_req_t payload;
12662 12661 fc_remote_port_t *pd;
12663 12662
12664 12663 rval = 0;
12665 12664
12666 12665 ASSERT(job != NULL);
12667 12666 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12668 12667
12669 12668 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12670 12669 if (pd == NULL) {
12671 12670 fctl_ns_req_t *ns_cmd;
12672 12671
12673 12672 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12674 12673 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12675 12674 0, sleep);
12676 12675
12677 12676 if (ns_cmd == NULL) {
12678 12677 return (FC_NOMEM);
12679 12678 }
12680 12679 job->job_result = FC_SUCCESS;
12681 12680 ns_cmd->ns_cmd_code = NS_GID_PN;
12682 12681 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12683 12682
12684 12683 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12685 12684 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12686 12685 fctl_free_ns_cmd(ns_cmd);
12687 12686 return (FC_FAILURE);
12688 12687 }
12689 12688 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12690 12689 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12691 12690
12692 12691 fctl_free_ns_cmd(ns_cmd);
12693 12692 lfa = d_id & 0xFFFF00;
12694 12693
12695 12694 /*
12696 12695 * Given this D_ID, get the port type to see if
12697 12696 * we can do LINIT on the LFA
12698 12697 */
12699 12698 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12700 12699 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12701 12700 0, sleep);
12702 12701
12703 12702 if (ns_cmd == NULL) {
12704 12703 return (FC_NOMEM);
12705 12704 }
12706 12705
12707 12706 job->job_result = FC_SUCCESS;
12708 12707 ns_cmd->ns_cmd_code = NS_GPT_ID;
12709 12708
12710 12709 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12711 12710 ((ns_req_gpt_id_t *)
12712 12711 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12713 12712
12714 12713 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12715 12714 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12716 12715 fctl_free_ns_cmd(ns_cmd);
12717 12716 return (FC_FAILURE);
12718 12717 }
12719 12718 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12720 12719
12721 12720 fctl_free_ns_cmd(ns_cmd);
12722 12721
12723 12722 switch (ptype.port_type) {
12724 12723 case FC_NS_PORT_NL:
12725 12724 case FC_NS_PORT_F_NL:
12726 12725 case FC_NS_PORT_FL:
12727 12726 break;
12728 12727
12729 12728 default:
12730 12729 return (FC_FAILURE);
12731 12730 }
12732 12731 } else {
12733 12732 mutex_enter(&pd->pd_mutex);
12734 12733 ptype = pd->pd_porttype;
12735 12734
12736 12735 switch (pd->pd_porttype.port_type) {
12737 12736 case FC_NS_PORT_NL:
12738 12737 case FC_NS_PORT_F_NL:
12739 12738 case FC_NS_PORT_FL:
12740 12739 lfa = pd->pd_port_id.port_id & 0xFFFF00;
12741 12740 break;
12742 12741
12743 12742 default:
12744 12743 mutex_exit(&pd->pd_mutex);
12745 12744 return (FC_FAILURE);
12746 12745 }
12747 12746 mutex_exit(&pd->pd_mutex);
12748 12747 }
12749 12748
12750 12749 mutex_enter(&port->fp_mutex);
12751 12750 s_id = port->fp_port_id.port_id;
12752 12751 class = port->fp_ns_login_class;
12753 12752 mutex_exit(&port->fp_mutex);
12754 12753
12755 12754 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12756 12755 sizeof (fc_linit_resp_t), sleep, pd);
12757 12756 if (cmd == NULL) {
12758 12757 return (FC_NOMEM);
12759 12758 }
12760 12759
12761 12760 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12762 12761 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12763 12762 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12764 12763 cmd->cmd_retry_count = fp_retry_count;
12765 12764 cmd->cmd_ulp_pkt = NULL;
12766 12765
12767 12766 pkt = &cmd->cmd_pkt;
12768 12767 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12769 12768
12770 12769 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12771 12770
12772 12771 /*
12773 12772 * How does LIP work by the way ?
12774 12773 * If the L_Port receives three consecutive identical ordered
12775 12774 * sets whose first two characters (fully decoded) are equal to
12776 12775 * the values shown in Table 3 of FC-AL-2 then the L_Port shall
12777 12776 * recognize a Loop Initialization Primitive sequence. The
12778 12777 * character 3 determines the type of lip:
12779 12778 * LIP(F7) Normal LIP
12780 12779 * LIP(F8) Loop Failure LIP
12781 12780 *
12782 12781 * The possible combination for the 3rd and 4th bytes are:
12783 12782 * F7, F7 Normal Lip - No valid AL_PA
12784 12783 * F8, F8 Loop Failure - No valid AL_PA
12785 12784 * F7, AL_PS Normal Lip - Valid source AL_PA
12786 12785 * F8, AL_PS Loop Failure - Valid source AL_PA
12787 12786 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS
12788 12787 * And Normal Lip for all other loop members
12789 12788 * 0xFF AL_PS Vendor specific reset of all loop members
12790 12789 *
12791 12790 * Now, it may not always be that we, at the source, may have an
12792 12791 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12793 12792 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12794 12793 * payload we are going to set:
12795 12794 * lip_b3 = 0xF7; Normal LIP
12796 12795 * lip_b4 = 0xF7; No valid source AL_PA
12797 12796 */
12798 12797 payload.ls_code.ls_code = LA_ELS_LINIT;
12799 12798 payload.ls_code.mbz = 0;
12800 12799 payload.rsvd = 0;
12801 12800 payload.func = 0; /* Let Fabric determine the best way */
12802 12801 payload.lip_b3 = 0xF7; /* Normal LIP */
12803 12802 payload.lip_b4 = 0xF7; /* No valid source AL_PA */
12804 12803
12805 12804 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12806 12805 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12807 12806
12808 12807 job->job_counter = 1;
12809 12808
12810 12809 ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12811 12810 if (ret == FC_SUCCESS) {
12812 12811 fp_jobwait(job);
12813 12812 rval = job->job_result;
12814 12813 } else {
12815 12814 rval = FC_FAILURE;
12816 12815 fp_free_pkt(cmd);
12817 12816 }
12818 12817
12819 12818 return (rval);
12820 12819 }
12821 12820
12822 12821
12823 12822 /*
12824 12823 * Fill out the device handles with GAN response
12825 12824 */
12826 12825 static void
12827 12826 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12828 12827 ns_resp_gan_t *gan_resp)
12829 12828 {
12830 12829 fc_remote_node_t *node;
12831 12830 fc_porttype_t type;
12832 12831 fc_local_port_t *port;
12833 12832
12834 12833 ASSERT(pd != NULL);
12835 12834 ASSERT(handle != NULL);
12836 12835
12837 12836 port = pd->pd_port;
12838 12837
12839 12838 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12840 12839 " port_id=%x, sym_len=%d fc4-type=%x",
12841 12840 pd, gan_resp->gan_type_id.rsvd,
12842 12841 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12843 12842
12844 12843 mutex_enter(&pd->pd_mutex);
12845 12844
12846 12845 FC_GET_RSP(port, *handle, (uint8_t *)&type,
12847 12846 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12848 12847
12849 12848 pd->pd_porttype.port_type = type.port_type;
12850 12849 pd->pd_porttype.rsvd = 0;
12851 12850
12852 12851 pd->pd_spn_len = gan_resp->gan_spnlen;
12853 12852 if (pd->pd_spn_len) {
12854 12853 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12855 12854 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12856 12855 DDI_DEV_AUTOINCR);
12857 12856 }
12858 12857
12859 12858 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12860 12859 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12861 12860 DDI_DEV_AUTOINCR);
12862 12861 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12863 12862 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12864 12863 DDI_DEV_AUTOINCR);
12865 12864 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12866 12865 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12867 12866 DDI_DEV_AUTOINCR);
12868 12867
12869 12868 node = pd->pd_remote_nodep;
12870 12869 mutex_exit(&pd->pd_mutex);
12871 12870
12872 12871 mutex_enter(&node->fd_mutex);
12873 12872
12874 12873 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12875 12874 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12876 12875 DDI_DEV_AUTOINCR);
12877 12876
12878 12877 node->fd_snn_len = gan_resp->gan_snnlen;
12879 12878 if (node->fd_snn_len) {
12880 12879 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12881 12880 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12882 12881 DDI_DEV_AUTOINCR);
12883 12882 }
12884 12883
12885 12884 mutex_exit(&node->fd_mutex);
12886 12885 }
12887 12886
12888 12887
12889 12888 /*
12890 12889 * Handles all NS Queries (also means that this function
12891 12890 * doesn't handle NS object registration)
12892 12891 */
12893 12892 static int
12894 12893 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12895 12894 int polled, int sleep)
12896 12895 {
12897 12896 int rval;
12898 12897 fp_cmd_t *cmd;
12899 12898
12900 12899 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12901 12900
12902 12901 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12903 12902 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12904 12903 port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12905 12904 }
12906 12905
12907 12906 if (ns_cmd->ns_cmd_size == 0) {
12908 12907 return (FC_FAILURE);
12909 12908 }
12910 12909
12911 12910 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12912 12911 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12913 12912 ns_cmd->ns_resp_size, sleep, NULL);
12914 12913 if (cmd == NULL) {
12915 12914 return (FC_NOMEM);
12916 12915 }
12917 12916
12918 12917 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12919 12918 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12920 12919
12921 12920 if (polled) {
12922 12921 job->job_counter = 1;
12923 12922 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12924 12923 }
12925 12924 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12926 12925 if (rval != FC_SUCCESS) {
12927 12926 job->job_result = rval;
12928 12927 fp_iodone(cmd);
12929 12928 if (polled == 0) {
12930 12929 /*
12931 12930 * Return FC_SUCCESS to indicate that
12932 12931 * fp_iodone is performed already.
12933 12932 */
12934 12933 rval = FC_SUCCESS;
12935 12934 }
12936 12935 }
12937 12936
12938 12937 if (polled) {
12939 12938 fp_jobwait(job);
12940 12939 rval = job->job_result;
12941 12940 }
12942 12941
12943 12942 return (rval);
12944 12943 }
12945 12944
12946 12945
12947 12946 /*
12948 12947 * Initialize Common Transport request
12949 12948 */
12950 12949 static void
12951 12950 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12952 12951 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12953 12952 uint16_t resp_len, job_request_t *job)
12954 12953 {
12955 12954 uint32_t s_id;
12956 12955 uchar_t class;
12957 12956 fc_packet_t *pkt;
12958 12957 fc_ct_header_t ct;
12959 12958
12960 12959 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12961 12960
12962 12961 mutex_enter(&port->fp_mutex);
12963 12962 s_id = port->fp_port_id.port_id;
12964 12963 class = port->fp_ns_login_class;
12965 12964 mutex_exit(&port->fp_mutex);
12966 12965
12967 12966 cmd->cmd_job = job;
12968 12967 cmd->cmd_private = ns_cmd;
12969 12968 pkt = &cmd->cmd_pkt;
12970 12969
12971 12970 ct.ct_rev = CT_REV;
12972 12971 ct.ct_inid = 0;
12973 12972 ct.ct_fcstype = FCSTYPE_DIRECTORY;
12974 12973 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12975 12974 ct.ct_options = 0;
12976 12975 ct.ct_reserved1 = 0;
12977 12976 ct.ct_cmdrsp = cmd_code;
12978 12977 ct.ct_aiusize = resp_len >> 2;
12979 12978 ct.ct_reserved2 = 0;
12980 12979 ct.ct_reason = 0;
12981 12980 ct.ct_expln = 0;
12982 12981 ct.ct_vendor = 0;
12983 12982
12984 12983 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12985 12984 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12986 12985
12987 12986 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12988 12987 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12989 12988 pkt->pkt_cmd_fhdr.s_id = s_id;
12990 12989 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12991 12990 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12992 12991 F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12993 12992 pkt->pkt_cmd_fhdr.seq_id = 0;
12994 12993 pkt->pkt_cmd_fhdr.df_ctl = 0;
12995 12994 pkt->pkt_cmd_fhdr.seq_cnt = 0;
12996 12995 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12997 12996 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12998 12997 pkt->pkt_cmd_fhdr.ro = 0;
12999 12998 pkt->pkt_cmd_fhdr.rsvd = 0;
13000 12999
13001 13000 pkt->pkt_comp = fp_ns_intr;
13002 13001 pkt->pkt_ulp_private = (opaque_t)cmd;
13003 13002 pkt->pkt_timeout = FP_NS_TIMEOUT;
13004 13003
13005 13004 if (cmd_buf) {
13006 13005 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
13007 13006 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13008 13007 cmd_len, DDI_DEV_AUTOINCR);
13009 13008 }
13010 13009
13011 13010 cmd->cmd_transport = port->fp_fca_tran->fca_transport;
13012 13011
13013 13012 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
13014 13013 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13015 13014 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
13016 13015 cmd->cmd_retry_count = fp_retry_count;
13017 13016 cmd->cmd_ulp_pkt = NULL;
13018 13017 }
13019 13018
13020 13019
13021 13020 /*
13022 13021 * Name Server request interrupt routine
13023 13022 */
13024 13023 static void
13025 13024 fp_ns_intr(fc_packet_t *pkt)
13026 13025 {
13027 13026 fp_cmd_t *cmd;
13028 13027 fc_local_port_t *port;
13029 13028 fc_ct_header_t resp_hdr;
13030 13029 fc_ct_header_t cmd_hdr;
13031 13030 fctl_ns_req_t *ns_cmd;
13032 13031
13033 13032 cmd = pkt->pkt_ulp_private;
13034 13033 port = cmd->cmd_port;
13035 13034
13036 13035 mutex_enter(&port->fp_mutex);
13037 13036 port->fp_out_fpcmds--;
13038 13037 mutex_exit(&port->fp_mutex);
13039 13038
13040 13039 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
13041 13040 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
13042 13041 ns_cmd = (fctl_ns_req_t *)
13043 13042 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
13044 13043 if (!FP_IS_PKT_ERROR(pkt)) {
13045 13044 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
13046 13045 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
13047 13046 DDI_DEV_AUTOINCR);
13048 13047
13049 13048 /*
13050 13049 * On x86 architectures, make sure the resp_hdr is big endian.
13051 13050 * This macro is a NOP on sparc architectures mainly because
13052 13051 * we don't want to end up wasting time since the end result
13053 13052 * is going to be the same.
13054 13053 */
13055 13054 MAKE_BE_32(&resp_hdr);
13056 13055
13057 13056 if (ns_cmd) {
13058 13057 /*
13059 13058 * Always copy out the response CT_HDR
13060 13059 */
13061 13060 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
13062 13061 sizeof (resp_hdr));
13063 13062 }
13064 13063
13065 13064 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
13066 13065 pkt->pkt_state = FC_PKT_FS_RJT;
13067 13066 pkt->pkt_reason = resp_hdr.ct_reason;
13068 13067 pkt->pkt_expln = resp_hdr.ct_expln;
13069 13068 }
13070 13069 }
13071 13070
13072 13071 if (FP_IS_PKT_ERROR(pkt)) {
13073 13072 if (ns_cmd) {
13074 13073 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13075 13074 ASSERT(ns_cmd->ns_pd != NULL);
13076 13075
13077 13076 /* Mark it OLD if not already done */
13078 13077 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13079 13078 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13080 13079 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13081 13080 }
13082 13081
13083 13082 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13084 13083 fctl_free_ns_cmd(ns_cmd);
13085 13084 ((fp_cmd_t *)
13086 13085 (pkt->pkt_ulp_private))->cmd_private = NULL;
13087 13086 }
13088 13087
13089 13088 }
13090 13089
13091 13090 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x "
13092 13091 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13093 13092 port->fp_port_id.port_id, pkt->pkt_state,
13094 13093 pkt->pkt_reason, pkt->pkt_expln,
13095 13094 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp);
13096 13095
13097 13096 (void) fp_common_intr(pkt, 1);
13098 13097
13099 13098 return;
13100 13099 }
13101 13100
13102 13101 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13103 13102 uint32_t d_id;
13104 13103 fc_local_port_t *port;
13105 13104 fp_cmd_t *cmd;
13106 13105
13107 13106 d_id = pkt->pkt_cmd_fhdr.d_id;
13108 13107 cmd = pkt->pkt_ulp_private;
13109 13108 port = cmd->cmd_port;
13110 13109 FP_TRACE(FP_NHEAD2(9, 0),
13111 13110 "Bogus NS response received for D_ID=%x", d_id);
13112 13111 }
13113 13112
13114 13113 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13115 13114 fp_gan_handler(pkt, ns_cmd);
13116 13115 return;
13117 13116 }
13118 13117
13119 13118 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13120 13119 cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13121 13120 if (ns_cmd) {
13122 13121 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13123 13122 fp_ns_query_handler(pkt, ns_cmd);
13124 13123 return;
13125 13124 }
13126 13125 }
13127 13126 }
13128 13127
13129 13128 fp_iodone(pkt->pkt_ulp_private);
13130 13129 }
13131 13130
13132 13131
13133 13132 /*
13134 13133 * Process NS_GAN response
13135 13134 */
13136 13135 static void
13137 13136 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13138 13137 {
13139 13138 int my_did;
13140 13139 fc_portid_t d_id;
13141 13140 fp_cmd_t *cmd;
13142 13141 fc_local_port_t *port;
13143 13142 fc_remote_port_t *pd;
13144 13143 ns_req_gan_t gan_req;
13145 13144 ns_resp_gan_t *gan_resp;
13146 13145
13147 13146 ASSERT(ns_cmd != NULL);
13148 13147
13149 13148 cmd = pkt->pkt_ulp_private;
13150 13149 port = cmd->cmd_port;
13151 13150
13152 13151 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13153 13152
13154 13153 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13155 13154 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13156 13155
13157 13156 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13158 13157
13159 13158 /*
13160 13159 * In this case the priv_lilp_posit field in reality
13161 13160 * is actually represents the relative position on a private loop.
13162 13161 * So zero it while dealing with Port Identifiers.
13163 13162 */
13164 13163 d_id.priv_lilp_posit = 0;
13165 13164 pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13166 13165 if (ns_cmd->ns_gan_sid == d_id.port_id) {
13167 13166 /*
13168 13167 * We've come a full circle; time to get out.
13169 13168 */
13170 13169 fp_iodone(cmd);
13171 13170 return;
13172 13171 }
13173 13172
13174 13173 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13175 13174 ns_cmd->ns_gan_sid = d_id.port_id;
13176 13175 }
13177 13176
13178 13177 mutex_enter(&port->fp_mutex);
13179 13178 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13180 13179 mutex_exit(&port->fp_mutex);
13181 13180
13182 13181 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13183 13182 port->fp_port_id.port_id, d_id.port_id);
13184 13183 if (my_did == 0) {
13185 13184 la_wwn_t pwwn;
13186 13185 la_wwn_t nwwn;
13187 13186
13188 13187 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13189 13188 "port=%p, d_id=%x, type_id=%x, "
13190 13189 "pwwn=%x %x %x %x %x %x %x %x, "
13191 13190 "nwwn=%x %x %x %x %x %x %x %x",
13192 13191 port, d_id.port_id, gan_resp->gan_type_id,
13193 13192
13194 13193 gan_resp->gan_pwwn.raw_wwn[0],
13195 13194 gan_resp->gan_pwwn.raw_wwn[1],
13196 13195 gan_resp->gan_pwwn.raw_wwn[2],
13197 13196 gan_resp->gan_pwwn.raw_wwn[3],
13198 13197 gan_resp->gan_pwwn.raw_wwn[4],
13199 13198 gan_resp->gan_pwwn.raw_wwn[5],
13200 13199 gan_resp->gan_pwwn.raw_wwn[6],
13201 13200 gan_resp->gan_pwwn.raw_wwn[7],
13202 13201
13203 13202 gan_resp->gan_nwwn.raw_wwn[0],
13204 13203 gan_resp->gan_nwwn.raw_wwn[1],
13205 13204 gan_resp->gan_nwwn.raw_wwn[2],
13206 13205 gan_resp->gan_nwwn.raw_wwn[3],
13207 13206 gan_resp->gan_nwwn.raw_wwn[4],
13208 13207 gan_resp->gan_nwwn.raw_wwn[5],
13209 13208 gan_resp->gan_nwwn.raw_wwn[6],
13210 13209 gan_resp->gan_nwwn.raw_wwn[7]);
13211 13210
13212 13211 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13213 13212 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13214 13213 DDI_DEV_AUTOINCR);
13215 13214
13216 13215 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13217 13216 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13218 13217 DDI_DEV_AUTOINCR);
13219 13218
13220 13219 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13221 13220 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13222 13221 "pd %x", port->fp_port_id.port_id, d_id.port_id);
13223 13222 pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13224 13223 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13225 13224 }
13226 13225 if (pd != NULL) {
13227 13226 fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13228 13227 pd, gan_resp);
13229 13228 }
13230 13229
13231 13230 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13232 13231 *((int *)ns_cmd->ns_data_buf) += 1;
13233 13232 }
13234 13233
13235 13234 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13236 13235 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13237 13236
13238 13237 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13239 13238 fc_port_dev_t *userbuf;
13240 13239
13241 13240 userbuf = ((fc_port_dev_t *)
13242 13241 ns_cmd->ns_data_buf) +
13243 13242 ns_cmd->ns_gan_index++;
13244 13243
13245 13244 userbuf->dev_did = d_id;
13246 13245
13247 13246 FC_GET_RSP(port, pkt->pkt_resp_acc,
13248 13247 (uint8_t *)userbuf->dev_type,
13249 13248 (uint8_t *)gan_resp->gan_fc4types,
13250 13249 sizeof (userbuf->dev_type),
13251 13250 DDI_DEV_AUTOINCR);
13252 13251
13253 13252 userbuf->dev_nwwn = nwwn;
13254 13253 userbuf->dev_pwwn = pwwn;
13255 13254
13256 13255 if (pd != NULL) {
13257 13256 mutex_enter(&pd->pd_mutex);
13258 13257 userbuf->dev_state = pd->pd_state;
13259 13258 userbuf->dev_hard_addr =
13260 13259 pd->pd_hard_addr;
13261 13260 mutex_exit(&pd->pd_mutex);
13262 13261 } else {
13263 13262 userbuf->dev_state =
13264 13263 PORT_DEVICE_INVALID;
13265 13264 }
13266 13265 } else if (ns_cmd->ns_flags &
13267 13266 FCTL_NS_BUF_IS_FC_PORTMAP) {
13268 13267 fc_portmap_t *map;
13269 13268
13270 13269 map = ((fc_portmap_t *)
13271 13270 ns_cmd->ns_data_buf) +
13272 13271 ns_cmd->ns_gan_index++;
13273 13272
13274 13273 /*
13275 13274 * First fill it like any new map
13276 13275 * and update the port device info
13277 13276 * below.
13278 13277 */
13279 13278 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13280 13279 map, gan_resp, d_id.port_id);
13281 13280 if (pd != NULL) {
13282 13281 fctl_copy_portmap(map, pd);
13283 13282 } else {
13284 13283 map->map_state = PORT_DEVICE_INVALID;
13285 13284 map->map_type = PORT_DEVICE_NOCHANGE;
13286 13285 }
13287 13286 } else {
13288 13287 caddr_t dst_ptr;
13289 13288
13290 13289 dst_ptr = ns_cmd->ns_data_buf +
13291 13290 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13292 13291
13293 13292 FC_GET_RSP(port, pkt->pkt_resp_acc,
13294 13293 (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13295 13294 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13296 13295 }
13297 13296 } else {
13298 13297 ns_cmd->ns_gan_index++;
13299 13298 }
13300 13299 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13301 13300 fp_iodone(cmd);
13302 13301 return;
13303 13302 }
13304 13303 }
13305 13304
13306 13305 gan_req.pid = d_id;
13307 13306
13308 13307 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13309 13308 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13310 13309 sizeof (gan_req), DDI_DEV_AUTOINCR);
13311 13310
13312 13311 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13313 13312 pkt->pkt_state = FC_PKT_TRAN_ERROR;
13314 13313 fp_iodone(cmd);
13315 13314 } else {
13316 13315 mutex_enter(&port->fp_mutex);
13317 13316 port->fp_out_fpcmds++;
13318 13317 mutex_exit(&port->fp_mutex);
13319 13318 }
13320 13319 }
13321 13320
13322 13321
13323 13322 /*
13324 13323 * Handle NS Query interrupt
13325 13324 */
13326 13325 static void
13327 13326 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13328 13327 {
13329 13328 fp_cmd_t *cmd;
13330 13329 fc_local_port_t *port;
13331 13330 caddr_t src_ptr;
13332 13331 uint32_t xfer_len;
13333 13332
13334 13333 cmd = pkt->pkt_ulp_private;
13335 13334 port = cmd->cmd_port;
13336 13335
13337 13336 xfer_len = ns_cmd->ns_resp_size;
13338 13337
13339 13338 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13340 13339 ns_cmd->ns_cmd_code, xfer_len);
13341 13340
13342 13341 if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13343 13342 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13344 13343
13345 13344 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13346 13345 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13347 13346 }
13348 13347
13349 13348 if (xfer_len <= ns_cmd->ns_data_len) {
13350 13349 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13351 13350 FC_GET_RSP(port, pkt->pkt_resp_acc,
13352 13351 (uint8_t *)ns_cmd->ns_data_buf,
13353 13352 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13354 13353 }
13355 13354
13356 13355 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13357 13356 ASSERT(ns_cmd->ns_pd != NULL);
13358 13357
13359 13358 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13360 13359 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13361 13360 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13362 13361 }
13363 13362 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13364 13363 }
13365 13364
13366 13365 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13367 13366 fctl_free_ns_cmd(ns_cmd);
13368 13367 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13369 13368 }
13370 13369 fp_iodone(cmd);
13371 13370 }
13372 13371
13373 13372
13374 13373 /*
13375 13374 * Handle unsolicited ADISC ELS request
13376 13375 */
13377 13376 static void
13378 13377 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13379 13378 fc_remote_port_t *pd, job_request_t *job)
13380 13379 {
13381 13380 int rval;
13382 13381 fp_cmd_t *cmd;
13383 13382
13384 13383 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13385 13384 port, pd->pd_port_id.port_id, pd->pd_state, pd);
13386 13385 mutex_enter(&pd->pd_mutex);
13387 13386 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13388 13387 mutex_exit(&pd->pd_mutex);
13389 13388 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13390 13389 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13391 13390 0, KM_SLEEP, pd);
13392 13391 if (cmd != NULL) {
13393 13392 fp_els_rjt_init(port, cmd, buf,
13394 13393 FC_ACTION_NON_RETRYABLE,
13395 13394 FC_REASON_INVALID_LINK_CTRL, job);
13396 13395
13397 13396 if (fp_sendcmd(port, cmd,
13398 13397 port->fp_fca_handle) != FC_SUCCESS) {
13399 13398 fp_free_pkt(cmd);
13400 13399 }
13401 13400 }
13402 13401 }
13403 13402 } else {
13404 13403 mutex_exit(&pd->pd_mutex);
13405 13404 /*
13406 13405 * Yes, yes, we don't have a hard address. But we
13407 13406 * we should still respond. Huh ? Visit 21.19.2
13408 13407 * of FC-PH-2 which essentially says that if an
13409 13408 * NL_Port doesn't have a hard address, or if a port
13410 13409 * does not have FC-AL capability, it shall report
13411 13410 * zeroes in this field.
13412 13411 */
13413 13412 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13414 13413 0, KM_SLEEP, pd);
13415 13414 if (cmd == NULL) {
13416 13415 return;
13417 13416 }
13418 13417 fp_adisc_acc_init(port, cmd, buf, job);
13419 13418 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13420 13419 if (rval != FC_SUCCESS) {
13421 13420 fp_free_pkt(cmd);
13422 13421 }
13423 13422 }
13424 13423 }
13425 13424
13426 13425
13427 13426 /*
13428 13427 * Initialize ADISC response.
13429 13428 */
13430 13429 static void
13431 13430 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13432 13431 job_request_t *job)
13433 13432 {
13434 13433 fc_packet_t *pkt;
13435 13434 la_els_adisc_t payload;
13436 13435
13437 13436 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13438 13437 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13439 13438 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13440 13439 cmd->cmd_retry_count = 1;
13441 13440 cmd->cmd_ulp_pkt = NULL;
13442 13441
13443 13442 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13444 13443 cmd->cmd_job = job;
13445 13444
13446 13445 pkt = &cmd->cmd_pkt;
13447 13446
13448 13447 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13449 13448
13450 13449 payload.ls_code.ls_code = LA_ELS_ACC;
13451 13450 payload.ls_code.mbz = 0;
13452 13451
13453 13452 mutex_enter(&port->fp_mutex);
13454 13453 payload.nport_id = port->fp_port_id;
13455 13454 payload.hard_addr = port->fp_hard_addr;
13456 13455 mutex_exit(&port->fp_mutex);
13457 13456
13458 13457 payload.port_wwn = port->fp_service_params.nport_ww_name;
13459 13458 payload.node_wwn = port->fp_service_params.node_ww_name;
13460 13459
13461 13460 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13462 13461 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13463 13462 }
13464 13463
13465 13464
13466 13465 /*
13467 13466 * Hold and Install the requested ULP drivers
13468 13467 */
13469 13468 static void
13470 13469 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13471 13470 {
13472 13471 int len;
13473 13472 int count;
13474 13473 int data_len;
13475 13474 major_t ulp_major;
13476 13475 caddr_t ulp_name;
13477 13476 caddr_t data_ptr;
13478 13477 caddr_t data_buf;
13479 13478
13480 13479 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13481 13480
13482 13481 data_buf = NULL;
13483 13482 if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13484 13483 DDI_PROP_DONTPASS, "load-ulp-list",
13485 13484 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13486 13485 return;
13487 13486 }
13488 13487
13489 13488 len = strlen(data_buf);
13490 13489 port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13491 13490
13492 13491 data_ptr = data_buf + len + 1;
13493 13492 for (count = 0; count < port->fp_ulp_nload; count++) {
13494 13493 len = strlen(data_ptr) + 1;
13495 13494 ulp_name = kmem_zalloc(len, KM_SLEEP);
13496 13495 bcopy(data_ptr, ulp_name, len);
13497 13496
13498 13497 ulp_major = ddi_name_to_major(ulp_name);
13499 13498
13500 13499 if (ulp_major != (major_t)-1) {
13501 13500 if (modload("drv", ulp_name) < 0) {
13502 13501 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13503 13502 0, NULL, "failed to load %s",
13504 13503 ulp_name);
13505 13504 }
13506 13505 } else {
13507 13506 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13508 13507 "%s isn't a valid driver", ulp_name);
13509 13508 }
13510 13509
13511 13510 kmem_free(ulp_name, len);
13512 13511 data_ptr += len; /* Skip to next field */
13513 13512 }
13514 13513
13515 13514 /*
13516 13515 * Free the memory allocated by DDI
13517 13516 */
13518 13517 if (data_buf != NULL) {
13519 13518 kmem_free(data_buf, data_len);
13520 13519 }
13521 13520 }
13522 13521
13523 13522
13524 13523 /*
13525 13524 * Perform LOGO operation
13526 13525 */
13527 13526 static int
13528 13527 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13529 13528 {
13530 13529 int rval;
13531 13530 fp_cmd_t *cmd;
13532 13531
13533 13532 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13534 13533 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13535 13534
13536 13535 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13537 13536 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13538 13537
13539 13538 mutex_enter(&port->fp_mutex);
13540 13539 mutex_enter(&pd->pd_mutex);
13541 13540
13542 13541 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13543 13542 ASSERT(pd->pd_login_count == 1);
13544 13543
13545 13544 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13546 13545 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13547 13546 cmd->cmd_flags = 0;
13548 13547 cmd->cmd_retry_count = 1;
13549 13548 cmd->cmd_ulp_pkt = NULL;
13550 13549
13551 13550 fp_logo_init(pd, cmd, job);
13552 13551
13553 13552 mutex_exit(&pd->pd_mutex);
13554 13553 mutex_exit(&port->fp_mutex);
13555 13554
13556 13555 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13557 13556 if (rval != FC_SUCCESS) {
13558 13557 fp_iodone(cmd);
13559 13558 }
13560 13559
13561 13560 return (rval);
13562 13561 }
13563 13562
13564 13563
13565 13564 /*
13566 13565 * Perform Port attach callbacks to registered ULPs
13567 13566 */
13568 13567 static void
13569 13568 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13570 13569 {
13571 13570 fp_soft_attach_t *att;
13572 13571
13573 13572 att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13574 13573 att->att_cmd = cmd;
13575 13574 att->att_port = port;
13576 13575
13577 13576 /*
13578 13577 * We need to remember whether or not fctl_busy_port
13579 13578 * succeeded so we know whether or not to call
13580 13579 * fctl_idle_port when the task is complete.
13581 13580 */
13582 13581
13583 13582 if (fctl_busy_port(port) == 0) {
13584 13583 att->att_need_pm_idle = B_TRUE;
13585 13584 } else {
13586 13585 att->att_need_pm_idle = B_FALSE;
13587 13586 }
13588 13587
13589 13588 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13590 13589 att, KM_SLEEP);
13591 13590 }
13592 13591
13593 13592
13594 13593 /*
13595 13594 * Forward state change notifications on to interested ULPs.
13596 13595 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13597 13596 * real work.
13598 13597 */
13599 13598 static int
13600 13599 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13601 13600 {
13602 13601 fc_port_clist_t *clist;
13603 13602
13604 13603 clist = kmem_zalloc(sizeof (*clist), sleep);
13605 13604 if (clist == NULL) {
13606 13605 return (FC_NOMEM);
13607 13606 }
13608 13607
13609 13608 clist->clist_state = statec;
13610 13609
13611 13610 mutex_enter(&port->fp_mutex);
13612 13611 clist->clist_flags = port->fp_topology;
13613 13612 mutex_exit(&port->fp_mutex);
13614 13613
13615 13614 clist->clist_port = (opaque_t)port;
13616 13615 clist->clist_len = 0;
13617 13616 clist->clist_size = 0;
13618 13617 clist->clist_map = NULL;
13619 13618
13620 13619 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13621 13620 clist, KM_SLEEP);
13622 13621
13623 13622 return (FC_SUCCESS);
13624 13623 }
13625 13624
13626 13625
13627 13626 /*
13628 13627 * Get name server map
13629 13628 */
13630 13629 static int
13631 13630 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13632 13631 uint32_t *len, uint32_t sid)
13633 13632 {
13634 13633 int ret;
13635 13634 fctl_ns_req_t *ns_cmd;
13636 13635
13637 13636 /*
13638 13637 * Don't let the allocator do anything for response;
13639 13638 * we have have buffer ready to fillout.
13640 13639 */
13641 13640 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13642 13641 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13643 13642 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13644 13643
13645 13644 ns_cmd->ns_data_len = sizeof (**map) * (*len);
13646 13645 ns_cmd->ns_data_buf = (caddr_t)*map;
13647 13646
13648 13647 ASSERT(ns_cmd != NULL);
13649 13648
13650 13649 ns_cmd->ns_gan_index = 0;
13651 13650 ns_cmd->ns_gan_sid = sid;
13652 13651 ns_cmd->ns_cmd_code = NS_GA_NXT;
13653 13652 ns_cmd->ns_gan_max = *len;
13654 13653
13655 13654 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13656 13655
13657 13656 if (ns_cmd->ns_gan_index != *len) {
13658 13657 *len = ns_cmd->ns_gan_index;
13659 13658 }
13660 13659 ns_cmd->ns_data_len = 0;
13661 13660 ns_cmd->ns_data_buf = NULL;
13662 13661 fctl_free_ns_cmd(ns_cmd);
13663 13662
13664 13663 return (ret);
13665 13664 }
13666 13665
13667 13666
13668 13667 /*
13669 13668 * Create a remote port in Fabric topology by using NS services
13670 13669 */
13671 13670 static fc_remote_port_t *
13672 13671 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13673 13672 {
13674 13673 int rval;
13675 13674 job_request_t *job;
13676 13675 fctl_ns_req_t *ns_cmd;
13677 13676 fc_remote_port_t *pd;
13678 13677
13679 13678 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13680 13679
13681 13680 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13682 13681 port, d_id);
13683 13682
13684 13683 #ifdef DEBUG
13685 13684 mutex_enter(&port->fp_mutex);
13686 13685 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13687 13686 mutex_exit(&port->fp_mutex);
13688 13687 #endif
13689 13688
13690 13689 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13691 13690 if (job == NULL) {
13692 13691 return (NULL);
13693 13692 }
13694 13693
13695 13694 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13696 13695 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13697 13696 FCTL_NS_NO_DATA_BUF), sleep);
13698 13697 if (ns_cmd == NULL) {
13699 13698 return (NULL);
13700 13699 }
13701 13700
13702 13701 job->job_result = FC_SUCCESS;
13703 13702 ns_cmd->ns_gan_max = 1;
13704 13703 ns_cmd->ns_cmd_code = NS_GA_NXT;
13705 13704 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13706 13705 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13707 13706 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13708 13707
13709 13708 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13710 13709 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13711 13710 fctl_free_ns_cmd(ns_cmd);
13712 13711
13713 13712 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13714 13713 fctl_dealloc_job(job);
13715 13714 return (NULL);
13716 13715 }
13717 13716 fctl_dealloc_job(job);
13718 13717
13719 13718 pd = fctl_get_remote_port_by_did(port, d_id);
13720 13719
13721 13720 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13722 13721 port, d_id, pd);
13723 13722
13724 13723 return (pd);
13725 13724 }
13726 13725
13727 13726
13728 13727 /*
13729 13728 * Check for the permissions on an ioctl command. If it is required to have an
13730 13729 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13731 13730 * the ioctl command isn't in one of the list built, shut the door on that too.
13732 13731 *
13733 13732 * Certain ioctls perform hardware accesses in FCA drivers, and it needs
13734 13733 * to be made sure that users open the port for an exclusive access while
13735 13734 * performing those operations.
13736 13735 *
13737 13736 * This can prevent a casual user from inflicting damage on the port by
13738 13737 * sending these ioctls from multiple processes/threads (there is no good
13739 13738 * reason why one would need to do that) without actually realizing how
13740 13739 * expensive such commands could turn out to be.
13741 13740 *
13742 13741 * It is also important to note that, even with an exclusive access,
13743 13742 * multiple threads can share the same file descriptor and fire down
13744 13743 * commands in parallel. To prevent that the driver needs to make sure
13745 13744 * that such commands aren't in progress already. This is taken care of
13746 13745 * in the FP_EXCL_BUSY bit of fp_flag.
13747 13746 */
13748 13747 static int
13749 13748 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13750 13749 {
13751 13750 int ret = FC_FAILURE;
13752 13751 int count;
13753 13752
13754 13753 for (count = 0;
13755 13754 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13756 13755 count++) {
13757 13756 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13758 13757 if (fp_perm_list[count].fp_open_flag & open_flag) {
13759 13758 ret = FC_SUCCESS;
13760 13759 }
13761 13760 break;
13762 13761 }
13763 13762 }
13764 13763
13765 13764 return (ret);
13766 13765 }
13767 13766
13768 13767
13769 13768 /*
13770 13769 * Bind Port driver's unsolicited, state change callbacks
13771 13770 */
13772 13771 static int
13773 13772 fp_bind_callbacks(fc_local_port_t *port)
13774 13773 {
13775 13774 fc_fca_bind_info_t bind_info = {0};
13776 13775 fc_fca_port_info_t *port_info;
13777 13776 int rval = DDI_SUCCESS;
13778 13777 uint16_t class;
13779 13778 int node_namelen, port_namelen;
13780 13779 char *nname = NULL, *pname = NULL;
13781 13780
13782 13781 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13783 13782
13784 13783 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13785 13784 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13786 13785 "node-name", &nname) != DDI_PROP_SUCCESS) {
13787 13786 FP_TRACE(FP_NHEAD1(1, 0),
13788 13787 "fp_bind_callback fail to get node-name");
13789 13788 }
13790 13789 if (nname) {
13791 13790 fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13792 13791 }
13793 13792
13794 13793 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13795 13794 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13796 13795 "port-name", &pname) != DDI_PROP_SUCCESS) {
13797 13796 FP_TRACE(FP_NHEAD1(1, 0),
13798 13797 "fp_bind_callback fail to get port-name");
13799 13798 }
13800 13799 if (pname) {
13801 13800 fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13802 13801 }
13803 13802
13804 13803 if (port->fp_npiv_type == FC_NPIV_PORT) {
13805 13804 bind_info.port_npiv = 1;
13806 13805 }
13807 13806
13808 13807 /*
13809 13808 * fca_bind_port returns the FCA driver's handle for the local
13810 13809 * port instance. If the port number isn't supported it returns NULL.
13811 13810 * It also sets up callback in the FCA for various
13812 13811 * things like state change, ELS etc..
13813 13812 */
13814 13813 bind_info.port_statec_cb = fp_statec_cb;
13815 13814 bind_info.port_unsol_cb = fp_unsol_cb;
13816 13815 bind_info.port_num = port->fp_port_num;
13817 13816 bind_info.port_handle = (opaque_t)port;
13818 13817
13819 13818 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13820 13819
13821 13820 /*
13822 13821 * Hold the port driver mutex as the callbacks are bound until the
13823 13822 * service parameters are properly filled in (in order to be able to
13824 13823 * properly respond to unsolicited ELS requests)
13825 13824 */
13826 13825 mutex_enter(&port->fp_mutex);
13827 13826
13828 13827 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13829 13828 port->fp_fca_dip, port_info, &bind_info);
13830 13829
13831 13830 if (port->fp_fca_handle == NULL) {
13832 13831 rval = DDI_FAILURE;
13833 13832 goto exit;
13834 13833 }
13835 13834
13836 13835 /*
13837 13836 * Only fcoei will set this bit
13838 13837 */
13839 13838 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13840 13839 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13841 13840 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13842 13841 }
13843 13842
13844 13843 port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13845 13844 port->fp_service_params = port_info->pi_login_params;
13846 13845 port->fp_hard_addr = port_info->pi_hard_addr;
13847 13846
13848 13847 /* Copy from the FCA structure to the FP structure */
13849 13848 port->fp_hba_port_attrs = port_info->pi_attrs;
13850 13849
13851 13850 if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13852 13851 port->fp_rnid_init = 1;
13853 13852 bcopy(&port_info->pi_rnid_params.params,
13854 13853 &port->fp_rnid_params,
13855 13854 sizeof (port->fp_rnid_params));
13856 13855 } else {
13857 13856 port->fp_rnid_init = 0;
13858 13857 }
13859 13858
13860 13859 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13861 13860 if (node_namelen) {
13862 13861 bcopy(&port_info->pi_attrs.sym_node_name,
13863 13862 &port->fp_sym_node_name,
13864 13863 node_namelen);
13865 13864 port->fp_sym_node_namelen = node_namelen;
13866 13865 }
13867 13866 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13868 13867 if (port_namelen) {
13869 13868 bcopy(&port_info->pi_attrs.sym_port_name,
13870 13869 &port->fp_sym_port_name,
13871 13870 port_namelen);
13872 13871 port->fp_sym_port_namelen = port_namelen;
13873 13872 }
13874 13873
13875 13874 /* zero out the normally unused fields right away */
13876 13875 port->fp_service_params.ls_code.mbz = 0;
13877 13876 port->fp_service_params.ls_code.ls_code = 0;
13878 13877 bzero(&port->fp_service_params.reserved,
13879 13878 sizeof (port->fp_service_params.reserved));
13880 13879
13881 13880 class = port_info->pi_login_params.class_1.class_opt;
13882 13881 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13883 13882
13884 13883 class = port_info->pi_login_params.class_2.class_opt;
13885 13884 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13886 13885
13887 13886 class = port_info->pi_login_params.class_3.class_opt;
13888 13887 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13889 13888
13890 13889 exit:
13891 13890 if (nname) {
13892 13891 ddi_prop_free(nname);
13893 13892 }
13894 13893 if (pname) {
13895 13894 ddi_prop_free(pname);
13896 13895 }
13897 13896 mutex_exit(&port->fp_mutex);
13898 13897 kmem_free(port_info, sizeof (*port_info));
13899 13898
13900 13899 return (rval);
13901 13900 }
13902 13901
13903 13902
13904 13903 /*
13905 13904 * Retrieve FCA capabilities
13906 13905 */
13907 13906 static void
13908 13907 fp_retrieve_caps(fc_local_port_t *port)
13909 13908 {
13910 13909 int rval;
13911 13910 int ub_count;
13912 13911 fc_fcp_dma_t fcp_dma;
13913 13912 fc_reset_action_t action;
13914 13913 fc_dma_behavior_t dma_behavior;
13915 13914
13916 13915 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13917 13916
13918 13917 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13919 13918 FC_CAP_UNSOL_BUF, &ub_count);
13920 13919
13921 13920 switch (rval) {
13922 13921 case FC_CAP_FOUND:
13923 13922 case FC_CAP_SETTABLE:
13924 13923 switch (ub_count) {
13925 13924 case 0:
13926 13925 break;
13927 13926
13928 13927 case -1:
13929 13928 ub_count = fp_unsol_buf_count;
13930 13929 break;
13931 13930
13932 13931 default:
13933 13932 /* 1/4th of total buffers is my share */
13934 13933 ub_count =
13935 13934 (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13936 13935 break;
13937 13936 }
13938 13937 break;
13939 13938
13940 13939 default:
13941 13940 ub_count = 0;
13942 13941 break;
13943 13942 }
13944 13943
13945 13944 mutex_enter(&port->fp_mutex);
13946 13945 port->fp_ub_count = ub_count;
13947 13946 mutex_exit(&port->fp_mutex);
13948 13947
13949 13948 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13950 13949 FC_CAP_POST_RESET_BEHAVIOR, &action);
13951 13950
13952 13951 switch (rval) {
13953 13952 case FC_CAP_FOUND:
13954 13953 case FC_CAP_SETTABLE:
13955 13954 switch (action) {
13956 13955 case FC_RESET_RETURN_NONE:
13957 13956 case FC_RESET_RETURN_ALL:
13958 13957 case FC_RESET_RETURN_OUTSTANDING:
13959 13958 break;
13960 13959
13961 13960 default:
13962 13961 action = FC_RESET_RETURN_NONE;
13963 13962 break;
13964 13963 }
13965 13964 break;
13966 13965
13967 13966 default:
13968 13967 action = FC_RESET_RETURN_NONE;
13969 13968 break;
13970 13969 }
13971 13970 mutex_enter(&port->fp_mutex);
13972 13971 port->fp_reset_action = action;
13973 13972 mutex_exit(&port->fp_mutex);
13974 13973
13975 13974 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13976 13975 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13977 13976
13978 13977 switch (rval) {
13979 13978 case FC_CAP_FOUND:
13980 13979 switch (dma_behavior) {
13981 13980 case FC_ALLOW_STREAMING:
13982 13981 /* FALLTHROUGH */
13983 13982 case FC_NO_STREAMING:
13984 13983 break;
13985 13984
13986 13985 default:
13987 13986 /*
13988 13987 * If capability was found and the value
13989 13988 * was incorrect assume the worst
13990 13989 */
13991 13990 dma_behavior = FC_NO_STREAMING;
13992 13991 break;
13993 13992 }
13994 13993 break;
13995 13994
13996 13995 default:
13997 13996 /*
13998 13997 * If capability was not defined - allow streaming; existing
13999 13998 * FCAs should not be affected.
14000 13999 */
14001 14000 dma_behavior = FC_ALLOW_STREAMING;
14002 14001 break;
14003 14002 }
14004 14003 mutex_enter(&port->fp_mutex);
14005 14004 port->fp_dma_behavior = dma_behavior;
14006 14005 mutex_exit(&port->fp_mutex);
14007 14006
14008 14007 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
14009 14008 FC_CAP_FCP_DMA, &fcp_dma);
14010 14009
14011 14010 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
14012 14011 fcp_dma != FC_DVMA_SPACE)) {
14013 14012 fcp_dma = FC_DVMA_SPACE;
14014 14013 }
14015 14014
14016 14015 mutex_enter(&port->fp_mutex);
14017 14016 port->fp_fcp_dma = fcp_dma;
14018 14017 mutex_exit(&port->fp_mutex);
14019 14018 }
14020 14019
14021 14020
14022 14021 /*
14023 14022 * Handle Domain, Area changes in the Fabric.
14024 14023 */
14025 14024 static void
14026 14025 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
14027 14026 job_request_t *job, int sleep)
14028 14027 {
14029 14028 #ifdef DEBUG
14030 14029 uint32_t dcnt;
14031 14030 #endif
14032 14031 int rval;
14033 14032 int send;
14034 14033 int index;
14035 14034 int listindex;
14036 14035 int login;
14037 14036 int job_flags;
14038 14037 char ww_name[17];
14039 14038 uint32_t d_id;
14040 14039 uint32_t count;
14041 14040 fctl_ns_req_t *ns_cmd;
14042 14041 fc_portmap_t *list;
14043 14042 fc_orphan_t *orp;
14044 14043 fc_orphan_t *norp;
14045 14044 fc_orphan_t *prev;
14046 14045 fc_remote_port_t *pd;
14047 14046 fc_remote_port_t *npd;
14048 14047 struct pwwn_hash *head;
14049 14048
14050 14049 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14051 14050 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14052 14051 0, sleep);
14053 14052 if (ns_cmd == NULL) {
14054 14053 mutex_enter(&port->fp_mutex);
14055 14054 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14056 14055 --port->fp_rscn_count;
14057 14056 }
14058 14057 mutex_exit(&port->fp_mutex);
14059 14058
14060 14059 return;
14061 14060 }
14062 14061 ns_cmd->ns_cmd_code = NS_GID_PN;
14063 14062
14064 14063 /*
14065 14064 * We need to get a new count of devices from the
14066 14065 * name server, which will also create any new devices
14067 14066 * as needed.
14068 14067 */
14069 14068
14070 14069 (void) fp_ns_get_devcount(port, job, 1, sleep);
14071 14070
14072 14071 FP_TRACE(FP_NHEAD1(3, 0),
14073 14072 "fp_validate_area_domain: get_devcount found %d devices",
14074 14073 port->fp_total_devices);
14075 14074
14076 14075 mutex_enter(&port->fp_mutex);
14077 14076
14078 14077 for (count = index = 0; index < pwwn_table_size; index++) {
14079 14078 head = &port->fp_pwwn_table[index];
14080 14079 pd = head->pwwn_head;
14081 14080 while (pd != NULL) {
14082 14081 mutex_enter(&pd->pd_mutex);
14083 14082 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14084 14083 if ((pd->pd_port_id.port_id & mask) == id &&
14085 14084 pd->pd_recepient == PD_PLOGI_INITIATOR) {
14086 14085 count++;
14087 14086 pd->pd_type = PORT_DEVICE_OLD;
14088 14087 pd->pd_flags = PD_ELS_MARK;
14089 14088 }
14090 14089 }
14091 14090 mutex_exit(&pd->pd_mutex);
14092 14091 pd = pd->pd_wwn_hnext;
14093 14092 }
14094 14093 }
14095 14094
14096 14095 #ifdef DEBUG
14097 14096 dcnt = count;
14098 14097 #endif /* DEBUG */
14099 14098
14100 14099 /*
14101 14100 * Since port->fp_orphan_count is declared an 'int' it is
14102 14101 * theoretically possible that the count could go negative.
14103 14102 *
14104 14103 * This would be bad and if that happens we really do want
14105 14104 * to know.
14106 14105 */
14107 14106
14108 14107 ASSERT(port->fp_orphan_count >= 0);
14109 14108
14110 14109 count += port->fp_orphan_count;
14111 14110
14112 14111 /*
14113 14112 * We add the port->fp_total_devices value to the count
14114 14113 * in the case where our port is newly attached. This is
14115 14114 * because we haven't done any discovery and we don't have
14116 14115 * any orphans in the port's orphan list. If we do not do
14117 14116 * this addition to count then we won't alloc enough kmem
14118 14117 * to do discovery with.
14119 14118 */
14120 14119
14121 14120 if (count == 0) {
14122 14121 count += port->fp_total_devices;
14123 14122 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14124 14123 "0x%x orphans found, using 0x%x",
14125 14124 port->fp_orphan_count, count);
14126 14125 }
14127 14126
14128 14127 mutex_exit(&port->fp_mutex);
14129 14128
14130 14129 /*
14131 14130 * Allocate the change list
14132 14131 */
14133 14132
14134 14133 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14135 14134 if (list == NULL) {
14136 14135 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14137 14136 " Not enough memory to service RSCNs"
14138 14137 " for %d ports, continuing...", count);
14139 14138
14140 14139 fctl_free_ns_cmd(ns_cmd);
14141 14140
14142 14141 mutex_enter(&port->fp_mutex);
14143 14142 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14144 14143 --port->fp_rscn_count;
14145 14144 }
14146 14145 mutex_exit(&port->fp_mutex);
14147 14146
14148 14147 return;
14149 14148 }
14150 14149
14151 14150 /*
14152 14151 * Attempt to validate or invalidate the devices that were
14153 14152 * already in the pwwn hash table.
14154 14153 */
14155 14154
14156 14155 mutex_enter(&port->fp_mutex);
14157 14156 for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14158 14157 head = &port->fp_pwwn_table[index];
14159 14158 npd = head->pwwn_head;
14160 14159
14161 14160 while ((pd = npd) != NULL) {
14162 14161 npd = pd->pd_wwn_hnext;
14163 14162
14164 14163 mutex_enter(&pd->pd_mutex);
14165 14164 if ((pd->pd_port_id.port_id & mask) == id &&
14166 14165 pd->pd_flags == PD_ELS_MARK) {
14167 14166 la_wwn_t *pwwn;
14168 14167
14169 14168 job->job_result = FC_SUCCESS;
14170 14169
14171 14170 ((ns_req_gid_pn_t *)
14172 14171 (ns_cmd->ns_cmd_buf))->pwwn =
14173 14172 pd->pd_port_name;
14174 14173
14175 14174 pwwn = &pd->pd_port_name;
14176 14175 d_id = pd->pd_port_id.port_id;
14177 14176
14178 14177 mutex_exit(&pd->pd_mutex);
14179 14178 mutex_exit(&port->fp_mutex);
14180 14179
14181 14180 rval = fp_ns_query(port, ns_cmd, job, 1,
14182 14181 sleep);
14183 14182 if (rval != FC_SUCCESS) {
14184 14183 fc_wwn_to_str(pwwn, ww_name);
14185 14184
14186 14185 FP_TRACE(FP_NHEAD1(3, 0),
14187 14186 "AREA RSCN: PD disappeared; "
14188 14187 "d_id=%x, PWWN=%s", d_id, ww_name);
14189 14188
14190 14189 FP_TRACE(FP_NHEAD2(9, 0),
14191 14190 "N_x Port with D_ID=%x,"
14192 14191 " PWWN=%s disappeared from fabric",
14193 14192 d_id, ww_name);
14194 14193
14195 14194 fp_fillout_old_map(list + listindex++,
14196 14195 pd, 1);
14197 14196 } else {
14198 14197 fctl_copy_portmap(list + listindex++,
14199 14198 pd);
14200 14199
14201 14200 mutex_enter(&pd->pd_mutex);
14202 14201 pd->pd_flags = PD_ELS_IN_PROGRESS;
14203 14202 mutex_exit(&pd->pd_mutex);
14204 14203 }
14205 14204
14206 14205 mutex_enter(&port->fp_mutex);
14207 14206 } else {
14208 14207 mutex_exit(&pd->pd_mutex);
14209 14208 }
14210 14209 }
14211 14210 }
14212 14211
14213 14212 mutex_exit(&port->fp_mutex);
14214 14213
14215 14214 ASSERT(listindex == dcnt);
14216 14215
14217 14216 job->job_counter = listindex;
14218 14217 job_flags = job->job_flags;
14219 14218 job->job_flags |= JOB_TYPE_FP_ASYNC;
14220 14219
14221 14220 /*
14222 14221 * Login (if we were the initiator) or validate devices in the
14223 14222 * port map.
14224 14223 */
14225 14224
14226 14225 for (index = 0; index < listindex; index++) {
14227 14226 pd = list[index].map_pd;
14228 14227
14229 14228 mutex_enter(&pd->pd_mutex);
14230 14229 ASSERT((pd->pd_port_id.port_id & mask) == id);
14231 14230
14232 14231 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14233 14232 ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14234 14233 mutex_exit(&pd->pd_mutex);
14235 14234 fp_jobdone(job);
14236 14235 continue;
14237 14236 }
14238 14237
14239 14238 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14240 14239 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14241 14240 d_id = pd->pd_port_id.port_id;
14242 14241 mutex_exit(&pd->pd_mutex);
14243 14242
14244 14243 if ((d_id & mask) == id && send) {
14245 14244 if (login) {
14246 14245 FP_TRACE(FP_NHEAD1(6, 0),
14247 14246 "RSCN and PLOGI request;"
14248 14247 " pd=%p, job=%p d_id=%x, index=%d", pd,
14249 14248 job, d_id, index);
14250 14249
14251 14250 rval = fp_port_login(port, d_id, job,
14252 14251 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14253 14252 if (rval != FC_SUCCESS) {
14254 14253 mutex_enter(&pd->pd_mutex);
14255 14254 pd->pd_flags = PD_IDLE;
14256 14255 mutex_exit(&pd->pd_mutex);
14257 14256
14258 14257 job->job_result = rval;
14259 14258 fp_jobdone(job);
14260 14259 }
14261 14260 FP_TRACE(FP_NHEAD1(1, 0),
14262 14261 "PLOGI succeeded:no skip(1) for "
14263 14262 "D_ID %x", d_id);
14264 14263 list[index].map_flags |=
14265 14264 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14266 14265 } else {
14267 14266 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14268 14267 " pd=%p, job=%p d_id=%x, index=%d", pd,
14269 14268 job, d_id, index);
14270 14269
14271 14270 rval = fp_ns_validate_device(port, pd, job,
14272 14271 0, sleep);
14273 14272 if (rval != FC_SUCCESS) {
14274 14273 fp_jobdone(job);
14275 14274 }
14276 14275 mutex_enter(&pd->pd_mutex);
14277 14276 pd->pd_flags = PD_IDLE;
14278 14277 mutex_exit(&pd->pd_mutex);
14279 14278 }
14280 14279 } else {
14281 14280 FP_TRACE(FP_NHEAD1(6, 0),
14282 14281 "RSCN and NO request sent; pd=%p,"
14283 14282 " d_id=%x, index=%d", pd, d_id, index);
14284 14283
14285 14284 mutex_enter(&pd->pd_mutex);
14286 14285 pd->pd_flags = PD_IDLE;
14287 14286 mutex_exit(&pd->pd_mutex);
14288 14287
14289 14288 fp_jobdone(job);
14290 14289 }
14291 14290 }
14292 14291
14293 14292 if (listindex) {
14294 14293 fctl_jobwait(job);
14295 14294 }
14296 14295 job->job_flags = job_flags;
14297 14296
14298 14297 /*
14299 14298 * Orphan list validation.
14300 14299 */
14301 14300 mutex_enter(&port->fp_mutex);
14302 14301 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14303 14302 orp != NULL; orp = norp) {
14304 14303 norp = orp->orp_next;
14305 14304 mutex_exit(&port->fp_mutex);
14306 14305
14307 14306 job->job_counter = 1;
14308 14307 job->job_result = FC_SUCCESS;
14309 14308 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14310 14309
14311 14310 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14312 14311
14313 14312 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14314 14313 ((ns_resp_gid_pn_t *)
14315 14314 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14316 14315
14317 14316 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14318 14317 if (rval == FC_SUCCESS) {
14319 14318 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14320 14319 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14321 14320 if (pd != NULL) {
14322 14321 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14323 14322
14324 14323 FP_TRACE(FP_NHEAD1(6, 0),
14325 14324 "RSCN and ORPHAN list "
14326 14325 "success; d_id=%x, PWWN=%s", d_id, ww_name);
14327 14326
14328 14327 FP_TRACE(FP_NHEAD2(6, 0),
14329 14328 "N_x Port with D_ID=%x, PWWN=%s reappeared"
14330 14329 " in fabric", d_id, ww_name);
14331 14330
14332 14331 mutex_enter(&port->fp_mutex);
14333 14332 if (prev) {
14334 14333 prev->orp_next = orp->orp_next;
14335 14334 } else {
14336 14335 ASSERT(orp == port->fp_orphan_list);
14337 14336 port->fp_orphan_list = orp->orp_next;
14338 14337 }
14339 14338 port->fp_orphan_count--;
14340 14339 mutex_exit(&port->fp_mutex);
14341 14340
14342 14341 kmem_free(orp, sizeof (*orp));
14343 14342 fctl_copy_portmap(list + listindex++, pd);
14344 14343 } else {
14345 14344 prev = orp;
14346 14345 }
14347 14346 } else {
14348 14347 prev = orp;
14349 14348 }
14350 14349 mutex_enter(&port->fp_mutex);
14351 14350 }
14352 14351 mutex_exit(&port->fp_mutex);
14353 14352
14354 14353 /*
14355 14354 * One more pass through the list to delist old devices from
14356 14355 * the d_id and pwwn tables and possibly add to the orphan list.
14357 14356 */
14358 14357
14359 14358 for (index = 0; index < listindex; index++) {
14360 14359 pd = list[index].map_pd;
14361 14360 ASSERT(pd != NULL);
14362 14361
14363 14362 /*
14364 14363 * Update PLOGI results; For NS validation
14365 14364 * of orphan list, it is redundant
14366 14365 *
14367 14366 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14368 14367 * appropriate as fctl_copy_portmap() will clear map_flags.
14369 14368 */
14370 14369 if (list[index].map_flags &
14371 14370 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14372 14371 fctl_copy_portmap(list + index, pd);
14373 14372 list[index].map_flags |=
14374 14373 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14375 14374 } else {
14376 14375 fctl_copy_portmap(list + index, pd);
14377 14376 }
14378 14377
14379 14378 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14380 14379 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14381 14380 pd, pd->pd_port_id.port_id,
14382 14381 pd->pd_port_name.raw_wwn[0],
14383 14382 pd->pd_port_name.raw_wwn[1],
14384 14383 pd->pd_port_name.raw_wwn[2],
14385 14384 pd->pd_port_name.raw_wwn[3],
14386 14385 pd->pd_port_name.raw_wwn[4],
14387 14386 pd->pd_port_name.raw_wwn[5],
14388 14387 pd->pd_port_name.raw_wwn[6],
14389 14388 pd->pd_port_name.raw_wwn[7]);
14390 14389
14391 14390 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14392 14391 "results continued, pd=%p type=%x, flags=%x, state=%x",
14393 14392 pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14394 14393
14395 14394 mutex_enter(&pd->pd_mutex);
14396 14395 if (pd->pd_type == PORT_DEVICE_OLD) {
14397 14396 int initiator;
14398 14397
14399 14398 pd->pd_flags = PD_IDLE;
14400 14399 initiator = (pd->pd_recepient ==
14401 14400 PD_PLOGI_INITIATOR) ? 1 : 0;
14402 14401
14403 14402 mutex_exit(&pd->pd_mutex);
14404 14403
14405 14404 mutex_enter(&port->fp_mutex);
14406 14405 mutex_enter(&pd->pd_mutex);
14407 14406
14408 14407 pd->pd_state = PORT_DEVICE_INVALID;
14409 14408 fctl_delist_did_table(port, pd);
14410 14409 fctl_delist_pwwn_table(port, pd);
14411 14410
14412 14411 mutex_exit(&pd->pd_mutex);
14413 14412 mutex_exit(&port->fp_mutex);
14414 14413
14415 14414 if (initiator) {
14416 14415 (void) fctl_add_orphan(port, pd, sleep);
14417 14416 }
14418 14417 list[index].map_pd = pd;
14419 14418 } else {
14420 14419 ASSERT(pd->pd_flags == PD_IDLE);
14421 14420 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14422 14421 /*
14423 14422 * Reset LOGO tolerance to zero
14424 14423 */
14425 14424 fctl_tc_reset(&pd->pd_logo_tc);
14426 14425 }
14427 14426 mutex_exit(&pd->pd_mutex);
14428 14427 }
14429 14428 }
14430 14429
14431 14430 if (ns_cmd) {
14432 14431 fctl_free_ns_cmd(ns_cmd);
14433 14432 }
14434 14433 if (listindex) {
14435 14434 (void) fp_ulp_devc_cb(port, list, listindex, count,
14436 14435 sleep, 0);
14437 14436 } else {
14438 14437 kmem_free(list, sizeof (*list) * count);
14439 14438
14440 14439 mutex_enter(&port->fp_mutex);
14441 14440 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14442 14441 --port->fp_rscn_count;
14443 14442 }
14444 14443 mutex_exit(&port->fp_mutex);
14445 14444 }
14446 14445 }
14447 14446
14448 14447
14449 14448 /*
14450 14449 * Work hard to make sense out of an RSCN page.
14451 14450 */
14452 14451 static void
14453 14452 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14454 14453 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14455 14454 int *listindex, int sleep)
14456 14455 {
14457 14456 int rval;
14458 14457 char ww_name[17];
14459 14458 la_wwn_t *pwwn;
14460 14459 fc_remote_port_t *pwwn_pd;
14461 14460 fc_remote_port_t *did_pd;
14462 14461
14463 14462 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14464 14463
14465 14464 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14466 14465 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14467 14466 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14468 14467
14469 14468 if (did_pd != NULL) {
14470 14469 mutex_enter(&did_pd->pd_mutex);
14471 14470 if (did_pd->pd_flags != PD_IDLE) {
14472 14471 mutex_exit(&did_pd->pd_mutex);
14473 14472 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14474 14473 "PD is BUSY; port=%p, d_id=%x, pd=%p",
14475 14474 port, page->aff_d_id, did_pd);
14476 14475 return;
14477 14476 }
14478 14477 did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14479 14478 mutex_exit(&did_pd->pd_mutex);
14480 14479 }
14481 14480
14482 14481 job->job_counter = 1;
14483 14482
14484 14483 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14485 14484
14486 14485 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14487 14486 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14488 14487
14489 14488 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14490 14489 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14491 14490
14492 14491 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14493 14492 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14494 14493 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14495 14494 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14496 14495 ns_cmd->ns_resp_hdr.ct_expln);
14497 14496
14498 14497 job->job_counter = 1;
14499 14498
14500 14499 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14501 14500 /*
14502 14501 * What this means is that the D_ID
14503 14502 * disappeared from the Fabric.
14504 14503 */
14505 14504 if (did_pd == NULL) {
14506 14505 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14507 14506 " NULL PD disappeared, rval=%x", rval);
14508 14507 return;
14509 14508 }
14510 14509
14511 14510 fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14512 14511
14513 14512 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14514 14513 (uint32_t)(uintptr_t)job->job_cb_arg;
14515 14514
14516 14515 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14517 14516
14518 14517 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14519 14518 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14520 14519
14521 14520 FP_TRACE(FP_NHEAD2(9, 0),
14522 14521 "GPN_ID for D_ID=%x failed", page->aff_d_id);
14523 14522
14524 14523 FP_TRACE(FP_NHEAD2(9, 0),
14525 14524 "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14526 14525 " fabric", page->aff_d_id, ww_name);
14527 14526
14528 14527 mutex_enter(&did_pd->pd_mutex);
14529 14528 did_pd->pd_flags = PD_IDLE;
14530 14529 mutex_exit(&did_pd->pd_mutex);
14531 14530
14532 14531 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14533 14532 "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14534 14533
14535 14534 return;
14536 14535 }
14537 14536
14538 14537 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14539 14538
14540 14539 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14541 14540 /*
14542 14541 * There is no change. Do PLOGI again and add it to
14543 14542 * ULP portmap baggage and return. Note: When RSCNs
14544 14543 * arrive with per page states, the need for PLOGI
14545 14544 * can be determined correctly.
14546 14545 */
14547 14546 mutex_enter(&pwwn_pd->pd_mutex);
14548 14547 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14549 14548 mutex_exit(&pwwn_pd->pd_mutex);
14550 14549
14551 14550 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14552 14551 (uint32_t)(uintptr_t)job->job_cb_arg;
14553 14552
14554 14553 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14555 14554
14556 14555 mutex_enter(&pwwn_pd->pd_mutex);
14557 14556 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14558 14557 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14559 14558 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14560 14559 mutex_exit(&pwwn_pd->pd_mutex);
14561 14560
14562 14561 rval = fp_port_login(port, page->aff_d_id, job,
14563 14562 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14564 14563 if (rval == FC_SUCCESS) {
14565 14564 fp_jobwait(job);
14566 14565 rval = job->job_result;
14567 14566
14568 14567 /*
14569 14568 * Reset LOGO tolerance to zero
14570 14569 * Also we are the PLOGI initiator now.
14571 14570 */
14572 14571 mutex_enter(&pwwn_pd->pd_mutex);
14573 14572 fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14574 14573 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14575 14574 mutex_exit(&pwwn_pd->pd_mutex);
14576 14575 }
14577 14576
14578 14577 if (rval == FC_SUCCESS) {
14579 14578 struct fc_portmap *map =
14580 14579 listptr + *listindex - 1;
14581 14580
14582 14581 FP_TRACE(FP_NHEAD1(1, 0),
14583 14582 "PLOGI succeeded: no skip(2)"
14584 14583 " for D_ID %x", page->aff_d_id);
14585 14584 map->map_flags |=
14586 14585 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14587 14586 } else {
14588 14587 FP_TRACE(FP_NHEAD2(9, rval),
14589 14588 "PLOGI to D_ID=%x failed", page->aff_d_id);
14590 14589
14591 14590 FP_TRACE(FP_NHEAD2(9, 0),
14592 14591 "N_x Port with D_ID=%x, PWWN=%s"
14593 14592 " disappeared from fabric",
14594 14593 page->aff_d_id, ww_name);
14595 14594
14596 14595 fp_fillout_old_map(listptr +
14597 14596 *listindex - 1, pwwn_pd, 0);
14598 14597 }
14599 14598 } else {
14600 14599 mutex_exit(&pwwn_pd->pd_mutex);
14601 14600 }
14602 14601
14603 14602 mutex_enter(&did_pd->pd_mutex);
14604 14603 did_pd->pd_flags = PD_IDLE;
14605 14604 mutex_exit(&did_pd->pd_mutex);
14606 14605
14607 14606 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14608 14607 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14609 14608 job->job_result, pwwn_pd);
14610 14609
14611 14610 return;
14612 14611 }
14613 14612
14614 14613 if (did_pd == NULL && pwwn_pd == NULL) {
14615 14614
14616 14615 fc_orphan_t *orp = NULL;
14617 14616 fc_orphan_t *norp = NULL;
14618 14617 fc_orphan_t *prev = NULL;
14619 14618
14620 14619 /*
14621 14620 * Hunt down the orphan list before giving up.
14622 14621 */
14623 14622
14624 14623 mutex_enter(&port->fp_mutex);
14625 14624 if (port->fp_orphan_count) {
14626 14625
14627 14626 for (orp = port->fp_orphan_list; orp; orp = norp) {
14628 14627 norp = orp->orp_next;
14629 14628
14630 14629 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14631 14630 prev = orp;
14632 14631 continue;
14633 14632 }
14634 14633
14635 14634 if (prev) {
14636 14635 prev->orp_next = orp->orp_next;
14637 14636 } else {
14638 14637 ASSERT(orp ==
14639 14638 port->fp_orphan_list);
14640 14639 port->fp_orphan_list =
14641 14640 orp->orp_next;
14642 14641 }
14643 14642 port->fp_orphan_count--;
14644 14643 break;
14645 14644 }
14646 14645 }
14647 14646
14648 14647 mutex_exit(&port->fp_mutex);
14649 14648 pwwn_pd = fp_create_remote_port_by_ns(port,
14650 14649 page->aff_d_id, sleep);
14651 14650
14652 14651 if (pwwn_pd != NULL) {
14653 14652
14654 14653 if (orp) {
14655 14654 fc_wwn_to_str(&orp->orp_pwwn,
14656 14655 ww_name);
14657 14656
14658 14657 FP_TRACE(FP_NHEAD2(9, 0),
14659 14658 "N_x Port with D_ID=%x,"
14660 14659 " PWWN=%s reappeared in fabric",
14661 14660 page->aff_d_id, ww_name);
14662 14661
14663 14662 kmem_free(orp, sizeof (*orp));
14664 14663 }
14665 14664
14666 14665 (listptr + *listindex)->
14667 14666 map_rscn_info.ulp_rscn_count =
14668 14667 (uint32_t)(uintptr_t)job->job_cb_arg;
14669 14668
14670 14669 fctl_copy_portmap(listptr +
14671 14670 (*listindex)++, pwwn_pd);
14672 14671 }
14673 14672
14674 14673 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14675 14674 "Case TWO", page->aff_d_id);
14676 14675
14677 14676 return;
14678 14677 }
14679 14678
14680 14679 if (pwwn_pd != NULL && did_pd == NULL) {
14681 14680 uint32_t old_d_id;
14682 14681 uint32_t d_id = page->aff_d_id;
14683 14682
14684 14683 /*
14685 14684 * What this means is there is a new D_ID for this
14686 14685 * Port WWN. Take out the port device off D_ID
14687 14686 * list and put it back with a new D_ID. Perform
14688 14687 * PLOGI if already logged in.
14689 14688 */
14690 14689 mutex_enter(&port->fp_mutex);
14691 14690 mutex_enter(&pwwn_pd->pd_mutex);
14692 14691
14693 14692 old_d_id = pwwn_pd->pd_port_id.port_id;
14694 14693
14695 14694 fctl_delist_did_table(port, pwwn_pd);
14696 14695
14697 14696 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14698 14697 (uint32_t)(uintptr_t)job->job_cb_arg;
14699 14698
14700 14699 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14701 14700 &d_id, NULL);
14702 14701 fctl_enlist_did_table(port, pwwn_pd);
14703 14702
14704 14703 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14705 14704 " Case THREE, pd=%p,"
14706 14705 " state=%x", pwwn_pd, pwwn_pd->pd_state);
14707 14706
14708 14707 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14709 14708 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14710 14709 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14711 14710
14712 14711 mutex_exit(&pwwn_pd->pd_mutex);
14713 14712 mutex_exit(&port->fp_mutex);
14714 14713
14715 14714 FP_TRACE(FP_NHEAD2(9, 0),
14716 14715 "N_x Port with D_ID=%x, PWWN=%s has a new"
14717 14716 " D_ID=%x now", old_d_id, ww_name, d_id);
14718 14717
14719 14718 rval = fp_port_login(port, page->aff_d_id, job,
14720 14719 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14721 14720 if (rval == FC_SUCCESS) {
14722 14721 fp_jobwait(job);
14723 14722 rval = job->job_result;
14724 14723 }
14725 14724
14726 14725 if (rval != FC_SUCCESS) {
14727 14726 fp_fillout_old_map(listptr +
14728 14727 *listindex - 1, pwwn_pd, 0);
14729 14728 }
14730 14729 } else {
14731 14730 mutex_exit(&pwwn_pd->pd_mutex);
14732 14731 mutex_exit(&port->fp_mutex);
14733 14732 }
14734 14733
14735 14734 return;
14736 14735 }
14737 14736
14738 14737 if (pwwn_pd == NULL && did_pd != NULL) {
14739 14738 fc_portmap_t *ptr;
14740 14739 uint32_t len = 1;
14741 14740 char old_ww_name[17];
14742 14741
14743 14742 mutex_enter(&did_pd->pd_mutex);
14744 14743 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14745 14744 mutex_exit(&did_pd->pd_mutex);
14746 14745
14747 14746 fc_wwn_to_str(pwwn, ww_name);
14748 14747
14749 14748 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14750 14749 (uint32_t)(uintptr_t)job->job_cb_arg;
14751 14750
14752 14751 /*
14753 14752 * What this means is that there is a new Port WWN for
14754 14753 * this D_ID; Mark the Port device as old and provide
14755 14754 * the new PWWN and D_ID combination as new.
14756 14755 */
14757 14756 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14758 14757
14759 14758 FP_TRACE(FP_NHEAD2(9, 0),
14760 14759 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14761 14760 page->aff_d_id, old_ww_name, ww_name);
14762 14761
14763 14762 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14764 14763 (uint32_t)(uintptr_t)job->job_cb_arg;
14765 14764
14766 14765 ptr = listptr + (*listindex)++;
14767 14766
14768 14767 job->job_counter = 1;
14769 14768
14770 14769 if (fp_ns_getmap(port, job, &ptr, &len,
14771 14770 page->aff_d_id - 1) != FC_SUCCESS) {
14772 14771 (*listindex)--;
14773 14772 }
14774 14773
14775 14774 mutex_enter(&did_pd->pd_mutex);
14776 14775 did_pd->pd_flags = PD_IDLE;
14777 14776 mutex_exit(&did_pd->pd_mutex);
14778 14777
14779 14778 return;
14780 14779 }
14781 14780
14782 14781 /*
14783 14782 * A weird case of Port WWN and D_ID existence but not matching up
14784 14783 * between them. Trust your instincts - Take the port device handle
14785 14784 * off Port WWN list, fix it with new Port WWN and put it back, In
14786 14785 * the mean time mark the port device corresponding to the old port
14787 14786 * WWN as OLD.
14788 14787 */
14789 14788 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14790 14789 " did_pd=%p", pwwn_pd, did_pd);
14791 14790
14792 14791 mutex_enter(&port->fp_mutex);
14793 14792 mutex_enter(&pwwn_pd->pd_mutex);
14794 14793
14795 14794 pwwn_pd->pd_type = PORT_DEVICE_OLD;
14796 14795 pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14797 14796 fctl_delist_did_table(port, pwwn_pd);
14798 14797 fctl_delist_pwwn_table(port, pwwn_pd);
14799 14798
14800 14799 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14801 14800 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14802 14801 pwwn_pd->pd_port_id.port_id,
14803 14802
14804 14803 pwwn_pd->pd_port_name.raw_wwn[0],
14805 14804 pwwn_pd->pd_port_name.raw_wwn[1],
14806 14805 pwwn_pd->pd_port_name.raw_wwn[2],
14807 14806 pwwn_pd->pd_port_name.raw_wwn[3],
14808 14807 pwwn_pd->pd_port_name.raw_wwn[4],
14809 14808 pwwn_pd->pd_port_name.raw_wwn[5],
14810 14809 pwwn_pd->pd_port_name.raw_wwn[6],
14811 14810 pwwn_pd->pd_port_name.raw_wwn[7]);
14812 14811
14813 14812 mutex_exit(&pwwn_pd->pd_mutex);
14814 14813 mutex_exit(&port->fp_mutex);
14815 14814
14816 14815 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14817 14816 (uint32_t)(uintptr_t)job->job_cb_arg;
14818 14817
14819 14818 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14820 14819
14821 14820 mutex_enter(&port->fp_mutex);
14822 14821 mutex_enter(&did_pd->pd_mutex);
14823 14822
14824 14823 fctl_delist_pwwn_table(port, did_pd);
14825 14824
14826 14825 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14827 14826 (uint32_t)(uintptr_t)job->job_cb_arg;
14828 14827
14829 14828 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14830 14829 fctl_enlist_pwwn_table(port, did_pd);
14831 14830
14832 14831 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14833 14832 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14834 14833 did_pd->pd_port_id.port_id, did_pd->pd_state,
14835 14834
14836 14835 did_pd->pd_port_name.raw_wwn[0],
14837 14836 did_pd->pd_port_name.raw_wwn[1],
14838 14837 did_pd->pd_port_name.raw_wwn[2],
14839 14838 did_pd->pd_port_name.raw_wwn[3],
14840 14839 did_pd->pd_port_name.raw_wwn[4],
14841 14840 did_pd->pd_port_name.raw_wwn[5],
14842 14841 did_pd->pd_port_name.raw_wwn[6],
14843 14842 did_pd->pd_port_name.raw_wwn[7]);
14844 14843
14845 14844 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14846 14845 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14847 14846 mutex_exit(&did_pd->pd_mutex);
14848 14847 mutex_exit(&port->fp_mutex);
14849 14848
14850 14849 rval = fp_port_login(port, page->aff_d_id, job,
14851 14850 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14852 14851 if (rval == FC_SUCCESS) {
14853 14852 fp_jobwait(job);
14854 14853 if (job->job_result != FC_SUCCESS) {
14855 14854 fp_fillout_old_map(listptr +
14856 14855 *listindex - 1, did_pd, 0);
14857 14856 }
14858 14857 } else {
14859 14858 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14860 14859 }
14861 14860 } else {
14862 14861 mutex_exit(&did_pd->pd_mutex);
14863 14862 mutex_exit(&port->fp_mutex);
14864 14863 }
14865 14864
14866 14865 mutex_enter(&did_pd->pd_mutex);
14867 14866 did_pd->pd_flags = PD_IDLE;
14868 14867 mutex_exit(&did_pd->pd_mutex);
14869 14868 }
14870 14869
14871 14870
14872 14871 /*
14873 14872 * Check with NS for the presence of this port WWN
14874 14873 */
14875 14874 static int
14876 14875 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14877 14876 job_request_t *job, int polled, int sleep)
14878 14877 {
14879 14878 la_wwn_t pwwn;
14880 14879 uint32_t flags;
14881 14880 fctl_ns_req_t *ns_cmd;
14882 14881
14883 14882 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14884 14883 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14885 14884 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14886 14885 flags, sleep);
14887 14886 if (ns_cmd == NULL) {
14888 14887 return (FC_NOMEM);
14889 14888 }
14890 14889
14891 14890 mutex_enter(&pd->pd_mutex);
14892 14891 pwwn = pd->pd_port_name;
14893 14892 mutex_exit(&pd->pd_mutex);
14894 14893
14895 14894 ns_cmd->ns_cmd_code = NS_GID_PN;
14896 14895 ns_cmd->ns_pd = pd;
14897 14896 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14898 14897 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14899 14898 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14900 14899
14901 14900 return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14902 14901 }
14903 14902
14904 14903
14905 14904 /*
14906 14905 * Sanity check the LILP map returned by FCA
14907 14906 */
14908 14907 static int
14909 14908 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14910 14909 {
14911 14910 int count;
14912 14911
14913 14912 if (lilp_map->lilp_length == 0) {
14914 14913 return (FC_FAILURE);
14915 14914 }
14916 14915
14917 14916 for (count = 0; count < lilp_map->lilp_length; count++) {
14918 14917 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14919 14918 FC_SUCCESS) {
14920 14919 return (FC_FAILURE);
14921 14920 }
14922 14921 }
14923 14922
14924 14923 return (FC_SUCCESS);
14925 14924 }
14926 14925
14927 14926
14928 14927 /*
14929 14928 * Sanity check if the AL_PA is a valid address
14930 14929 */
14931 14930 static int
14932 14931 fp_is_valid_alpa(uchar_t al_pa)
14933 14932 {
14934 14933 int count;
14935 14934
14936 14935 for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14937 14936 if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14938 14937 return (FC_SUCCESS);
14939 14938 }
14940 14939 }
14941 14940
14942 14941 return (FC_FAILURE);
14943 14942 }
14944 14943
14945 14944
14946 14945 /*
14947 14946 * Post unsolicited callbacks to ULPs
14948 14947 */
14949 14948 static void
14950 14949 fp_ulp_unsol_cb(void *arg)
14951 14950 {
14952 14951 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg;
14953 14952
14954 14953 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14955 14954 ub_spec->buf->ub_frame.type);
14956 14955 kmem_free(ub_spec, sizeof (*ub_spec));
14957 14956 }
14958 14957
14959 14958
14960 14959 /*
14961 14960 * Perform message reporting in a consistent manner. Unless there is
14962 14961 * a strong reason NOT to use this function (which is very very rare)
14963 14962 * all message reporting should go through this.
14964 14963 */
14965 14964 static void
14966 14965 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14967 14966 fc_packet_t *pkt, const char *fmt, ...)
14968 14967 {
14969 14968 caddr_t buf;
14970 14969 va_list ap;
14971 14970
14972 14971 switch (level) {
14973 14972 case CE_NOTE:
14974 14973 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14975 14974 return;
14976 14975 }
14977 14976 break;
14978 14977
14979 14978 case CE_WARN:
14980 14979 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14981 14980 return;
14982 14981 }
14983 14982 break;
14984 14983 }
14985 14984
14986 14985 buf = kmem_zalloc(256, KM_NOSLEEP);
14987 14986 if (buf == NULL) {
14988 14987 return;
14989 14988 }
14990 14989
14991 14990 (void) sprintf(buf, "fp(%d): ", port->fp_instance);
14992 14991
14993 14992 va_start(ap, fmt);
14994 14993 (void) vsprintf(buf + strlen(buf), fmt, ap);
14995 14994 va_end(ap);
14996 14995
14997 14996 if (fc_errno) {
14998 14997 char *errmsg;
14999 14998
15000 14999 (void) fc_ulp_error(fc_errno, &errmsg);
15001 15000 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
15002 15001 } else {
15003 15002 if (pkt) {
15004 15003 caddr_t state, reason, action, expln;
15005 15004
15006 15005 (void) fc_ulp_pkt_error(pkt, &state, &reason,
15007 15006 &action, &expln);
15008 15007
15009 15008 (void) sprintf(buf + strlen(buf),
15010 15009 " state=%s, reason=%s", state, reason);
15011 15010
15012 15011 if (pkt->pkt_resp_resid) {
15013 15012 (void) sprintf(buf + strlen(buf),
15014 15013 " resp resid=%x\n", pkt->pkt_resp_resid);
15015 15014 }
15016 15015 }
15017 15016 }
15018 15017
15019 15018 switch (dest) {
15020 15019 case FP_CONSOLE_ONLY:
15021 15020 cmn_err(level, "^%s", buf);
15022 15021 break;
15023 15022
15024 15023 case FP_LOG_ONLY:
15025 15024 cmn_err(level, "!%s", buf);
15026 15025 break;
15027 15026
15028 15027 default:
15029 15028 cmn_err(level, "%s", buf);
15030 15029 break;
15031 15030 }
15032 15031
15033 15032 kmem_free(buf, 256);
15034 15033 }
15035 15034
15036 15035 static int
15037 15036 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15038 15037 {
15039 15038 int ret;
15040 15039 uint32_t d_id;
15041 15040 la_wwn_t pwwn;
15042 15041 fc_remote_port_t *pd = NULL;
15043 15042 fc_remote_port_t *held_pd = NULL;
15044 15043 fctl_ns_req_t *ns_cmd;
15045 15044 fc_portmap_t *changelist;
15046 15045
15047 15046 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15048 15047
15049 15048 mutex_enter(&port->fp_mutex);
15050 15049 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15051 15050 mutex_exit(&port->fp_mutex);
15052 15051 job->job_counter = 1;
15053 15052
15054 15053 job->job_result = FC_SUCCESS;
15055 15054
15056 15055 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
15057 15056 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
15058 15057 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
15059 15058
15060 15059 ASSERT(ns_cmd != NULL);
15061 15060
15062 15061 ns_cmd->ns_cmd_code = NS_GID_PN;
15063 15062 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
15064 15063
15065 15064 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
15066 15065
15067 15066 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15068 15067 if (ret != FC_SUCCESS) {
15069 15068 fcio->fcio_errno = ret;
15070 15069 } else {
15071 15070 fcio->fcio_errno = job->job_result;
15072 15071 }
15073 15072 fctl_free_ns_cmd(ns_cmd);
15074 15073 return (EIO);
15075 15074 }
15076 15075 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15077 15076 fctl_free_ns_cmd(ns_cmd);
15078 15077 } else {
15079 15078 mutex_exit(&port->fp_mutex);
15080 15079
15081 15080 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15082 15081 if (held_pd == NULL) {
15083 15082 fcio->fcio_errno = FC_BADWWN;
15084 15083 return (EIO);
15085 15084 }
15086 15085 pd = held_pd;
15087 15086
15088 15087 mutex_enter(&pd->pd_mutex);
15089 15088 d_id = pd->pd_port_id.port_id;
15090 15089 mutex_exit(&pd->pd_mutex);
15091 15090 }
15092 15091
15093 15092 job->job_counter = 1;
15094 15093
15095 15094 pd = fctl_get_remote_port_by_did(port, d_id);
15096 15095
15097 15096 if (pd) {
15098 15097 mutex_enter(&pd->pd_mutex);
15099 15098 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15100 15099 pd->pd_login_count++;
15101 15100 mutex_exit(&pd->pd_mutex);
15102 15101
15103 15102 fcio->fcio_errno = FC_SUCCESS;
15104 15103 if (held_pd) {
15105 15104 fctl_release_remote_port(held_pd);
15106 15105 }
15107 15106
15108 15107 return (0);
15109 15108 }
15110 15109 mutex_exit(&pd->pd_mutex);
15111 15110 } else {
15112 15111 mutex_enter(&port->fp_mutex);
15113 15112 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15114 15113 mutex_exit(&port->fp_mutex);
15115 15114 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15116 15115 if (pd == NULL) {
15117 15116 fcio->fcio_errno = FC_FAILURE;
15118 15117 if (held_pd) {
15119 15118 fctl_release_remote_port(held_pd);
15120 15119 }
15121 15120 return (EIO);
15122 15121 }
15123 15122 } else {
15124 15123 mutex_exit(&port->fp_mutex);
15125 15124 }
15126 15125 }
15127 15126
15128 15127 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15129 15128 job->job_counter = 1;
15130 15129
15131 15130 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15132 15131 KM_SLEEP, pd, NULL);
15133 15132
15134 15133 if (ret != FC_SUCCESS) {
15135 15134 fcio->fcio_errno = ret;
15136 15135 if (held_pd) {
15137 15136 fctl_release_remote_port(held_pd);
15138 15137 }
15139 15138 return (EIO);
15140 15139 }
15141 15140 fp_jobwait(job);
15142 15141
15143 15142 fcio->fcio_errno = job->job_result;
15144 15143
15145 15144 if (held_pd) {
15146 15145 fctl_release_remote_port(held_pd);
15147 15146 }
15148 15147
15149 15148 if (job->job_result != FC_SUCCESS) {
15150 15149 return (EIO);
15151 15150 }
15152 15151
15153 15152 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15154 15153 if (pd == NULL) {
15155 15154 fcio->fcio_errno = FC_BADDEV;
15156 15155 return (ENODEV);
15157 15156 }
15158 15157
15159 15158 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15160 15159
15161 15160 fctl_copy_portmap(changelist, pd);
15162 15161 changelist->map_type = PORT_DEVICE_USER_LOGIN;
15163 15162
15164 15163 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15165 15164
15166 15165 mutex_enter(&pd->pd_mutex);
15167 15166 pd->pd_type = PORT_DEVICE_NOCHANGE;
15168 15167 mutex_exit(&pd->pd_mutex);
15169 15168
15170 15169 fctl_release_remote_port(pd);
15171 15170
15172 15171 return (0);
15173 15172 }
15174 15173
15175 15174
15176 15175 static int
15177 15176 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15178 15177 {
15179 15178 la_wwn_t pwwn;
15180 15179 fp_cmd_t *cmd;
15181 15180 fc_portmap_t *changelist;
15182 15181 fc_remote_port_t *pd;
15183 15182
15184 15183 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15185 15184
15186 15185 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15187 15186 if (pd == NULL) {
15188 15187 fcio->fcio_errno = FC_BADWWN;
15189 15188 return (ENXIO);
15190 15189 }
15191 15190
15192 15191 mutex_enter(&pd->pd_mutex);
15193 15192 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15194 15193 fcio->fcio_errno = FC_LOGINREQ;
15195 15194 mutex_exit(&pd->pd_mutex);
15196 15195
15197 15196 fctl_release_remote_port(pd);
15198 15197
15199 15198 return (EINVAL);
15200 15199 }
15201 15200
15202 15201 ASSERT(pd->pd_login_count >= 1);
15203 15202
15204 15203 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15205 15204 fcio->fcio_errno = FC_FAILURE;
15206 15205 mutex_exit(&pd->pd_mutex);
15207 15206
15208 15207 fctl_release_remote_port(pd);
15209 15208
15210 15209 return (EBUSY);
15211 15210 }
15212 15211
15213 15212 if (pd->pd_login_count > 1) {
15214 15213 pd->pd_login_count--;
15215 15214 fcio->fcio_errno = FC_SUCCESS;
15216 15215 mutex_exit(&pd->pd_mutex);
15217 15216
15218 15217 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15219 15218
15220 15219 fctl_copy_portmap(changelist, pd);
15221 15220 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15222 15221
15223 15222 fctl_release_remote_port(pd);
15224 15223
15225 15224 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15226 15225
15227 15226 return (0);
15228 15227 }
15229 15228
15230 15229 pd->pd_flags = PD_ELS_IN_PROGRESS;
15231 15230 mutex_exit(&pd->pd_mutex);
15232 15231
15233 15232 job->job_counter = 1;
15234 15233
15235 15234 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15236 15235 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15237 15236 if (cmd == NULL) {
15238 15237 fcio->fcio_errno = FC_NOMEM;
15239 15238 fctl_release_remote_port(pd);
15240 15239
15241 15240 mutex_enter(&pd->pd_mutex);
15242 15241 pd->pd_flags = PD_IDLE;
15243 15242 mutex_exit(&pd->pd_mutex);
15244 15243
15245 15244 return (ENOMEM);
15246 15245 }
15247 15246
15248 15247 mutex_enter(&port->fp_mutex);
15249 15248 mutex_enter(&pd->pd_mutex);
15250 15249
15251 15250 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15252 15251 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15253 15252 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15254 15253 cmd->cmd_retry_count = 1;
15255 15254 cmd->cmd_ulp_pkt = NULL;
15256 15255
15257 15256 fp_logo_init(pd, cmd, job);
15258 15257
15259 15258 mutex_exit(&pd->pd_mutex);
15260 15259 mutex_exit(&port->fp_mutex);
15261 15260
15262 15261 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15263 15262 mutex_enter(&pd->pd_mutex);
15264 15263 pd->pd_flags = PD_IDLE;
15265 15264 mutex_exit(&pd->pd_mutex);
15266 15265
15267 15266 fp_free_pkt(cmd);
15268 15267 fctl_release_remote_port(pd);
15269 15268
15270 15269 return (EIO);
15271 15270 }
15272 15271
15273 15272 fp_jobwait(job);
15274 15273
15275 15274 fcio->fcio_errno = job->job_result;
15276 15275 if (job->job_result != FC_SUCCESS) {
15277 15276 mutex_enter(&pd->pd_mutex);
15278 15277 pd->pd_flags = PD_IDLE;
15279 15278 mutex_exit(&pd->pd_mutex);
15280 15279
15281 15280 fctl_release_remote_port(pd);
15282 15281
15283 15282 return (EIO);
15284 15283 }
15285 15284
15286 15285 ASSERT(pd != NULL);
15287 15286
15288 15287 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15289 15288
15290 15289 fctl_copy_portmap(changelist, pd);
15291 15290 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15292 15291 changelist->map_state = PORT_DEVICE_INVALID;
15293 15292
15294 15293 mutex_enter(&port->fp_mutex);
15295 15294 mutex_enter(&pd->pd_mutex);
15296 15295
15297 15296 fctl_delist_did_table(port, pd);
15298 15297 fctl_delist_pwwn_table(port, pd);
15299 15298 pd->pd_flags = PD_IDLE;
15300 15299
15301 15300 mutex_exit(&pd->pd_mutex);
15302 15301 mutex_exit(&port->fp_mutex);
15303 15302
15304 15303 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15305 15304
15306 15305 fctl_release_remote_port(pd);
15307 15306
15308 15307 return (0);
15309 15308 }
15310 15309
15311 15310
15312 15311
15313 15312 /*
15314 15313 * Send a syslog event for adapter port level events.
15315 15314 */
15316 15315 static void
15317 15316 fp_log_port_event(fc_local_port_t *port, char *subclass)
15318 15317 {
15319 15318 nvlist_t *attr_list;
15320 15319
15321 15320 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15322 15321 KM_SLEEP) != DDI_SUCCESS) {
15323 15322 goto alloc_failed;
15324 15323 }
15325 15324
15326 15325 if (nvlist_add_uint32(attr_list, "instance",
15327 15326 port->fp_instance) != DDI_SUCCESS) {
15328 15327 goto error;
15329 15328 }
15330 15329
15331 15330 if (nvlist_add_byte_array(attr_list, "port-wwn",
15332 15331 port->fp_service_params.nport_ww_name.raw_wwn,
15333 15332 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15334 15333 goto error;
15335 15334 }
15336 15335
15337 15336 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15338 15337 subclass, attr_list, NULL, DDI_SLEEP);
15339 15338
15340 15339 nvlist_free(attr_list);
15341 15340 return;
15342 15341
15343 15342 error:
15344 15343 nvlist_free(attr_list);
15345 15344 alloc_failed:
15346 15345 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15347 15346 }
15348 15347
15349 15348
15350 15349 static void
15351 15350 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15352 15351 uint32_t port_id)
15353 15352 {
15354 15353 nvlist_t *attr_list;
15355 15354
15356 15355 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15357 15356 KM_SLEEP) != DDI_SUCCESS) {
15358 15357 goto alloc_failed;
15359 15358 }
15360 15359
15361 15360 if (nvlist_add_uint32(attr_list, "instance",
15362 15361 port->fp_instance) != DDI_SUCCESS) {
15363 15362 goto error;
15364 15363 }
15365 15364
15366 15365 if (nvlist_add_byte_array(attr_list, "port-wwn",
15367 15366 port->fp_service_params.nport_ww_name.raw_wwn,
15368 15367 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15369 15368 goto error;
15370 15369 }
15371 15370
15372 15371 if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15373 15372 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15374 15373 goto error;
15375 15374 }
15376 15375
15377 15376 if (nvlist_add_uint32(attr_list, "target-port-id",
15378 15377 port_id) != DDI_SUCCESS) {
15379 15378 goto error;
15380 15379 }
15381 15380
15382 15381 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15383 15382 subclass, attr_list, NULL, DDI_SLEEP);
15384 15383
15385 15384 nvlist_free(attr_list);
15386 15385 return;
15387 15386
15388 15387 error:
15389 15388 nvlist_free(attr_list);
15390 15389 alloc_failed:
15391 15390 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15392 15391 }
15393 15392
15394 15393 static uint32_t
15395 15394 fp_map_remote_port_state(uint32_t rm_state)
15396 15395 {
15397 15396 switch (rm_state) {
15398 15397 case PORT_DEVICE_LOGGED_IN:
15399 15398 return (FC_HBA_PORTSTATE_ONLINE);
15400 15399 case PORT_DEVICE_VALID:
15401 15400 case PORT_DEVICE_INVALID:
15402 15401 default:
15403 15402 return (FC_HBA_PORTSTATE_UNKNOWN);
15404 15403 }
15405 15404 }
↓ open down ↓ |
15284 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX