Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/impl/fp.c
+++ new/usr/src/uts/common/io/fibre-channel/impl/fp.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 *
24 24 * NOT a DDI compliant Sun Fibre Channel port driver(fp)
25 25 *
26 26 */
27 27
28 28 #include <sys/types.h>
29 29 #include <sys/varargs.h>
30 30 #include <sys/param.h>
31 31 #include <sys/errno.h>
32 32 #include <sys/uio.h>
33 33 #include <sys/buf.h>
34 34 #include <sys/modctl.h>
35 35 #include <sys/open.h>
36 36 #include <sys/file.h>
37 37 #include <sys/kmem.h>
38 38 #include <sys/poll.h>
39 39 #include <sys/conf.h>
40 40 #include <sys/thread.h>
41 41 #include <sys/var.h>
42 42 #include <sys/cmn_err.h>
43 43 #include <sys/stat.h>
44 44 #include <sys/ddi.h>
45 45 #include <sys/sunddi.h>
46 46 #include <sys/promif.h>
47 47 #include <sys/nvpair.h>
48 48 #include <sys/byteorder.h>
49 49 #include <sys/scsi/scsi.h>
50 50 #include <sys/fibre-channel/fc.h>
51 51 #include <sys/fibre-channel/impl/fc_ulpif.h>
52 52 #include <sys/fibre-channel/impl/fc_fcaif.h>
53 53 #include <sys/fibre-channel/impl/fctl_private.h>
54 54 #include <sys/fibre-channel/impl/fc_portif.h>
55 55 #include <sys/fibre-channel/impl/fp.h>
56 56
57 57 /* These are defined in fctl.c! */
58 58 extern int did_table_size;
59 59 extern int pwwn_table_size;
60 60
61 61 static struct cb_ops fp_cb_ops = {
62 62 fp_open, /* open */
63 63 fp_close, /* close */
64 64 nodev, /* strategy */
65 65 nodev, /* print */
66 66 nodev, /* dump */
67 67 nodev, /* read */
68 68 nodev, /* write */
69 69 fp_ioctl, /* ioctl */
70 70 nodev, /* devmap */
71 71 nodev, /* mmap */
72 72 nodev, /* segmap */
73 73 nochpoll, /* chpoll */
74 74 ddi_prop_op, /* cb_prop_op */
75 75 0, /* streamtab */
76 76 D_NEW | D_MP | D_HOTPLUG, /* cb_flag */
77 77 CB_REV, /* rev */
78 78 nodev, /* aread */
79 79 nodev /* awrite */
80 80 };
81 81
82 82 static struct dev_ops fp_ops = {
83 83 DEVO_REV, /* build revision */
84 84 0, /* reference count */
85 85 fp_getinfo, /* getinfo */
86 86 nulldev, /* identify - Obsoleted */
87 87 nulldev, /* probe */
88 88 fp_attach, /* attach */
89 89 fp_detach, /* detach */
90 90 nodev, /* reset */
91 91 &fp_cb_ops, /* cb_ops */
92 92 NULL, /* bus_ops */
93 93 fp_power, /* power */
94 94 ddi_quiesce_not_needed /* quiesce */
95 95 };
96 96
97 97 #define FP_VERSION "20091123-1.101"
98 98 #define FP_NAME_VERSION "SunFC Port v" FP_VERSION
99 99
100 100 char *fp_version = FP_NAME_VERSION;
101 101
102 102 static struct modldrv modldrv = {
103 103 &mod_driverops, /* Type of Module */
104 104 FP_NAME_VERSION, /* Name/Version of fp */
105 105 &fp_ops /* driver ops */
106 106 };
107 107
108 108 static struct modlinkage modlinkage = {
109 109 MODREV_1, /* Rev of the loadable modules system */
110 110 &modldrv, /* NULL terminated list of */
111 111 NULL /* Linkage structures */
112 112 };
113 113
114 114
115 115
116 116 static uint16_t ns_reg_cmds[] = {
117 117 NS_RPN_ID,
118 118 NS_RNN_ID,
119 119 NS_RCS_ID,
120 120 NS_RFT_ID,
121 121 NS_RPT_ID,
122 122 NS_RSPN_ID,
123 123 NS_RSNN_NN
124 124 };
125 125
126 126 struct fp_xlat {
127 127 uchar_t xlat_state;
128 128 int xlat_rval;
129 129 } fp_xlat [] = {
130 130 { FC_PKT_SUCCESS, FC_SUCCESS },
131 131 { FC_PKT_REMOTE_STOP, FC_FAILURE },
132 132 { FC_PKT_LOCAL_RJT, FC_FAILURE },
133 133 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT },
134 134 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT },
135 135 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY },
136 136 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY },
137 137 { FC_PKT_NPORT_BSY, FC_PBUSY },
138 138 { FC_PKT_FABRIC_BSY, FC_FBUSY },
139 139 { FC_PKT_LS_RJT, FC_FAILURE },
140 140 { FC_PKT_BA_RJT, FC_FAILURE },
141 141 { FC_PKT_TIMEOUT, FC_FAILURE },
142 142 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR },
143 143 { FC_PKT_FAILURE, FC_FAILURE },
144 144 { FC_PKT_PORT_OFFLINE, FC_OFFLINE }
145 145 };
146 146
147 147 static uchar_t fp_valid_alpas[] = {
148 148 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
149 149 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
150 150 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
151 151 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
152 152 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
153 153 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
154 154 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
155 155 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
156 156 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
157 157 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
158 158 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
159 159 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
160 160 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
161 161 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
162 162 };
163 163
164 164 static struct fp_perms {
165 165 uint16_t fp_ioctl_cmd;
166 166 uchar_t fp_open_flag;
167 167 } fp_perm_list [] = {
168 168 { FCIO_GET_NUM_DEVS, FP_OPEN },
169 169 { FCIO_GET_DEV_LIST, FP_OPEN },
170 170 { FCIO_GET_SYM_PNAME, FP_OPEN },
171 171 { FCIO_GET_SYM_NNAME, FP_OPEN },
172 172 { FCIO_SET_SYM_PNAME, FP_EXCL },
173 173 { FCIO_SET_SYM_NNAME, FP_EXCL },
174 174 { FCIO_GET_LOGI_PARAMS, FP_OPEN },
175 175 { FCIO_DEV_LOGIN, FP_EXCL },
176 176 { FCIO_DEV_LOGOUT, FP_EXCL },
177 177 { FCIO_GET_STATE, FP_OPEN },
178 178 { FCIO_DEV_REMOVE, FP_EXCL },
179 179 { FCIO_GET_FCODE_REV, FP_OPEN },
180 180 { FCIO_GET_FW_REV, FP_OPEN },
181 181 { FCIO_GET_DUMP_SIZE, FP_OPEN },
182 182 { FCIO_FORCE_DUMP, FP_EXCL },
183 183 { FCIO_GET_DUMP, FP_OPEN },
184 184 { FCIO_GET_TOPOLOGY, FP_OPEN },
185 185 { FCIO_RESET_LINK, FP_EXCL },
186 186 { FCIO_RESET_HARD, FP_EXCL },
187 187 { FCIO_RESET_HARD_CORE, FP_EXCL },
188 188 { FCIO_DIAG, FP_OPEN },
189 189 { FCIO_NS, FP_EXCL },
190 190 { FCIO_DOWNLOAD_FW, FP_EXCL },
191 191 { FCIO_DOWNLOAD_FCODE, FP_EXCL },
192 192 { FCIO_LINK_STATUS, FP_OPEN },
193 193 { FCIO_GET_HOST_PARAMS, FP_OPEN },
194 194 { FCIO_GET_NODE_ID, FP_OPEN },
195 195 { FCIO_SET_NODE_ID, FP_EXCL },
196 196 { FCIO_SEND_NODE_ID, FP_OPEN },
197 197 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN },
198 198 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN },
199 199 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN },
200 200 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN },
201 201 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN },
202 202 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN },
203 203 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
204 204 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
205 205 { FCIO_DELETE_NPIV_PORT, FP_OPEN },
206 206 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
207 207 { FCIO_CREATE_NPIV_PORT, FP_OPEN },
208 208 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
209 209 };
210 210
211 211 static char *fp_pm_comps[] = {
212 212 "NAME=FC Port",
213 213 "0=Port Down",
214 214 "1=Port Up"
215 215 };
216 216
217 217
218 218 #ifdef _LITTLE_ENDIAN
219 219 #define MAKE_BE_32(x) { \
220 220 uint32_t *ptr1, i; \
221 221 ptr1 = (uint32_t *)(x); \
222 222 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
223 223 *ptr1 = BE_32(*ptr1); \
224 224 ptr1++; \
225 225 } \
226 226 }
227 227 #else
228 228 #define MAKE_BE_32(x)
229 229 #endif
230 230
231 231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
232 232 static uint32_t fp_options = 0;
233 233
234 234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
235 235 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */
236 236 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */
237 237 unsigned int fp_offline_ticker; /* seconds */
238 238
239 239 /*
240 240 * Driver global variable to anchor the list of soft state structs for
241 241 * all fp driver instances. Used with the Solaris DDI soft state functions.
242 242 */
243 243 static void *fp_driver_softstate;
244 244
245 245 static clock_t fp_retry_ticks;
246 246 static clock_t fp_offline_ticks;
247 247
248 248 static int fp_retry_ticker;
249 249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
250 250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
251 251
252 252 static int fp_log_size = FP_LOG_SIZE;
253 253 static int fp_trace = FP_TRACE_DEFAULT;
254 254 static fc_trace_logq_t *fp_logq = NULL;
255 255
256 256 int fp_get_adapter_paths(char *pathList, int count);
257 257 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
258 258 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
259 259 la_wwn_t tgt_pwwn, uint32_t port_id);
260 260 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
261 261 static void fp_init_symbolic_names(fc_local_port_t *port);
262 262
263 263
264 264 /*
265 265 * Perform global initialization
266 266 */
267 267 int
268 268 _init(void)
269 269 {
270 270 int ret;
271 271
272 272 if ((ret = ddi_soft_state_init(&fp_driver_softstate,
273 273 sizeof (struct fc_local_port), 8)) != 0) {
274 274 return (ret);
275 275 }
276 276
277 277 if ((ret = scsi_hba_init(&modlinkage)) != 0) {
278 278 ddi_soft_state_fini(&fp_driver_softstate);
279 279 return (ret);
280 280 }
281 281
282 282 fp_logq = fc_trace_alloc_logq(fp_log_size);
283 283
284 284 if ((ret = mod_install(&modlinkage)) != 0) {
285 285 fc_trace_free_logq(fp_logq);
286 286 ddi_soft_state_fini(&fp_driver_softstate);
287 287 scsi_hba_fini(&modlinkage);
288 288 }
289 289
290 290 return (ret);
291 291 }
292 292
293 293
294 294 /*
295 295 * Prepare for driver unload
296 296 */
297 297 int
298 298 _fini(void)
299 299 {
300 300 int ret;
301 301
302 302 if ((ret = mod_remove(&modlinkage)) == 0) {
303 303 fc_trace_free_logq(fp_logq);
304 304 ddi_soft_state_fini(&fp_driver_softstate);
305 305 scsi_hba_fini(&modlinkage);
306 306 }
307 307
308 308 return (ret);
309 309 }
310 310
311 311
312 312 /*
313 313 * Request mod_info() to handle all cases
314 314 */
315 315 int
316 316 _info(struct modinfo *modinfo)
317 317 {
318 318 return (mod_info(&modlinkage, modinfo));
319 319 }
320 320
321 321
322 322 /*
323 323 * fp_attach:
324 324 *
325 325 * The respective cmd handlers take care of performing
326 326 * ULP related invocations
327 327 */
328 328 static int
329 329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
330 330 {
331 331 int rval;
332 332
333 333 /*
334 334 * We check the value of fp_offline_ticker at this
335 335 * point. The variable is global for the driver and
336 336 * not specific to an instance.
337 337 *
338 338 * If there is no user-defined value found in /etc/system
339 339 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
340 340 * The minimum setting for this offline timeout according
341 341 * to the FC-FS2 standard (Fibre Channel Framing and
342 342 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
343 343 *
344 344 * We do not recommend setting the value to less than 10
345 345 * seconds (RA_TOV) or more than 90 seconds. If this
346 346 * variable is greater than 90 seconds then drivers above
347 347 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
348 348 */
349 349
350 350 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
351 351 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
352 352 FP_OFFLINE_TICKER);
353 353
354 354 if ((fp_offline_ticker < 10) ||
355 355 (fp_offline_ticker > 90)) {
356 356 cmn_err(CE_WARN, "Setting fp_offline_ticker to "
357 357 "%d second(s). This is outside the "
358 358 "recommended range of 10..90 seconds",
359 359 fp_offline_ticker);
360 360 }
361 361
362 362 /*
363 363 * Tick every second when there are commands to retry.
364 364 * It should tick at the least granular value of pkt_timeout
365 365 * (which is one second)
366 366 */
367 367 fp_retry_ticker = 1;
368 368
369 369 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
370 370 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
371 371
372 372 switch (cmd) {
373 373 case DDI_ATTACH:
374 374 rval = fp_attach_handler(dip);
375 375 break;
376 376
377 377 case DDI_RESUME:
378 378 rval = fp_resume_handler(dip);
379 379 break;
380 380
381 381 default:
382 382 rval = DDI_FAILURE;
383 383 break;
384 384 }
385 385 return (rval);
386 386 }
387 387
388 388
389 389 /*
390 390 * fp_detach:
391 391 *
392 392 * If a ULP fails to handle cmd request converse of
393 393 * cmd is invoked for ULPs that previously succeeded
394 394 * cmd request.
395 395 */
396 396 static int
397 397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
398 398 {
399 399 int rval = DDI_FAILURE;
400 400 fc_local_port_t *port;
401 401 fc_attach_cmd_t converse;
402 402 uint8_t cnt;
403 403
404 404 if ((port = ddi_get_soft_state(fp_driver_softstate,
405 405 ddi_get_instance(dip))) == NULL) {
406 406 return (DDI_FAILURE);
407 407 }
408 408
409 409 mutex_enter(&port->fp_mutex);
410 410
411 411 if (port->fp_ulp_attach) {
412 412 mutex_exit(&port->fp_mutex);
413 413 return (DDI_FAILURE);
414 414 }
415 415
416 416 switch (cmd) {
417 417 case DDI_DETACH:
418 418 if (port->fp_task != FP_TASK_IDLE) {
419 419 mutex_exit(&port->fp_mutex);
420 420 return (DDI_FAILURE);
421 421 }
422 422
423 423 /* Let's attempt to quit the job handler gracefully */
424 424 port->fp_soft_state |= FP_DETACH_INPROGRESS;
425 425
426 426 mutex_exit(&port->fp_mutex);
427 427 converse = FC_CMD_ATTACH;
428 428 if (fctl_detach_ulps(port, FC_CMD_DETACH,
429 429 &modlinkage) != FC_SUCCESS) {
430 430 mutex_enter(&port->fp_mutex);
↓ open down ↓ |
430 lines elided |
↑ open up ↑ |
431 431 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
432 432 mutex_exit(&port->fp_mutex);
433 433 rval = DDI_FAILURE;
434 434 break;
435 435 }
436 436
437 437 mutex_enter(&port->fp_mutex);
438 438 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
439 439 cnt++) {
440 440 mutex_exit(&port->fp_mutex);
441 - delay(drv_usectohz(1000000));
441 + delay(drv_sectohz(1));
442 442 mutex_enter(&port->fp_mutex);
443 443 }
444 444
445 445 if (port->fp_job_head) {
446 446 mutex_exit(&port->fp_mutex);
447 447 rval = DDI_FAILURE;
448 448 break;
449 449 }
450 450 mutex_exit(&port->fp_mutex);
451 451
452 452 rval = fp_detach_handler(port);
453 453 break;
454 454
455 455 case DDI_SUSPEND:
456 456 mutex_exit(&port->fp_mutex);
457 457 converse = FC_CMD_RESUME;
458 458 if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
459 459 &modlinkage) != FC_SUCCESS) {
460 460 rval = DDI_FAILURE;
461 461 break;
462 462 }
463 463 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
464 464 (void) callb_generic_cpr(&port->fp_cpr_info,
465 465 CB_CODE_CPR_RESUME);
466 466 }
467 467 break;
468 468
469 469 default:
470 470 mutex_exit(&port->fp_mutex);
471 471 break;
472 472 }
473 473
474 474 /*
475 475 * Use softint to perform reattach. Mark fp_ulp_attach so we
476 476 * don't attempt to do this repeatedly on behalf of some persistent
477 477 * caller.
478 478 */
479 479 if (rval != DDI_SUCCESS) {
480 480 mutex_enter(&port->fp_mutex);
481 481 port->fp_ulp_attach = 1;
482 482
483 483 /*
484 484 * If the port is in the low power mode then there is
485 485 * possibility that fca too could be in low power mode.
486 486 * Try to raise the power before calling attach ulps.
487 487 */
488 488
489 489 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
490 490 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
491 491 mutex_exit(&port->fp_mutex);
492 492 (void) pm_raise_power(port->fp_port_dip,
493 493 FP_PM_COMPONENT, FP_PM_PORT_UP);
494 494 } else {
495 495 mutex_exit(&port->fp_mutex);
496 496 }
497 497
498 498
499 499 fp_attach_ulps(port, converse);
500 500
501 501 mutex_enter(&port->fp_mutex);
502 502 while (port->fp_ulp_attach) {
503 503 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
504 504 }
505 505
506 506 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
507 507
508 508 /*
509 509 * Mark state as detach failed so asynchronous ULP attach
510 510 * events (downstream, not the ones we're initiating with
511 511 * the call to fp_attach_ulps) are not honored. We're
512 512 * really still in pending detach.
513 513 */
514 514 port->fp_soft_state |= FP_DETACH_FAILED;
515 515
516 516 mutex_exit(&port->fp_mutex);
517 517 }
518 518
519 519 return (rval);
520 520 }
521 521
522 522
523 523 /*
524 524 * fp_getinfo:
525 525 * Given the device number, return either the
526 526 * dev_info_t pointer or the instance number.
527 527 */
528 528
529 529 /* ARGSUSED */
530 530 static int
531 531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
532 532 {
533 533 int rval;
534 534 minor_t instance;
535 535 fc_local_port_t *port;
536 536
537 537 rval = DDI_SUCCESS;
538 538 instance = getminor((dev_t)arg);
539 539
540 540 switch (cmd) {
541 541 case DDI_INFO_DEVT2DEVINFO:
542 542 if ((port = ddi_get_soft_state(fp_driver_softstate,
543 543 instance)) == NULL) {
544 544 rval = DDI_FAILURE;
545 545 break;
546 546 }
547 547 *result = (void *)port->fp_port_dip;
548 548 break;
549 549
550 550 case DDI_INFO_DEVT2INSTANCE:
551 551 *result = (void *)(uintptr_t)instance;
552 552 break;
553 553
554 554 default:
555 555 rval = DDI_FAILURE;
556 556 break;
557 557 }
558 558
559 559 return (rval);
560 560 }
561 561
562 562
563 563 /*
564 564 * Entry point for power up and power down request from kernel
565 565 */
566 566 static int
567 567 fp_power(dev_info_t *dip, int comp, int level)
568 568 {
569 569 int rval = DDI_FAILURE;
570 570 fc_local_port_t *port;
571 571
572 572 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
573 573 if (port == NULL || comp != FP_PM_COMPONENT) {
574 574 return (rval);
575 575 }
576 576
577 577 switch (level) {
578 578 case FP_PM_PORT_UP:
579 579 rval = DDI_SUCCESS;
580 580
581 581 /*
582 582 * If the port is DDI_SUSPENDed, let the DDI_RESUME
583 583 * code complete the rediscovery.
584 584 */
585 585 mutex_enter(&port->fp_mutex);
586 586 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
587 587 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
588 588 port->fp_pm_level = FP_PM_PORT_UP;
589 589 mutex_exit(&port->fp_mutex);
590 590 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
591 591 break;
592 592 }
593 593
594 594 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
595 595 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
596 596
597 597 port->fp_pm_level = FP_PM_PORT_UP;
598 598 rval = fp_power_up(port);
599 599 if (rval != DDI_SUCCESS) {
600 600 port->fp_pm_level = FP_PM_PORT_DOWN;
601 601 }
602 602 } else {
603 603 port->fp_pm_level = FP_PM_PORT_UP;
604 604 }
605 605 mutex_exit(&port->fp_mutex);
606 606 break;
607 607
608 608 case FP_PM_PORT_DOWN:
609 609 mutex_enter(&port->fp_mutex);
610 610
611 611 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
612 612 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
613 613 /*
614 614 * PM framework goofed up. We have don't
615 615 * have any PM components. Let's never go down.
616 616 */
617 617 mutex_exit(&port->fp_mutex);
618 618 break;
619 619
620 620 }
621 621
622 622 if (port->fp_ulp_attach) {
623 623 /* We shouldn't let the power go down */
624 624 mutex_exit(&port->fp_mutex);
625 625 break;
626 626 }
627 627
628 628 /*
629 629 * Not a whole lot to do if we are detaching
630 630 */
631 631 if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
632 632 port->fp_pm_level = FP_PM_PORT_DOWN;
633 633 mutex_exit(&port->fp_mutex);
634 634 rval = DDI_SUCCESS;
635 635 break;
636 636 }
637 637
638 638 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
639 639 port->fp_pm_level = FP_PM_PORT_DOWN;
640 640
641 641 rval = fp_power_down(port);
642 642 if (rval != DDI_SUCCESS) {
643 643 port->fp_pm_level = FP_PM_PORT_UP;
644 644 ASSERT(!(port->fp_soft_state &
645 645 FP_SOFT_POWER_DOWN));
646 646 } else {
647 647 ASSERT(port->fp_soft_state &
648 648 FP_SOFT_POWER_DOWN);
649 649 }
650 650 }
651 651 mutex_exit(&port->fp_mutex);
652 652 break;
653 653
654 654 default:
655 655 break;
656 656 }
657 657
658 658 return (rval);
659 659 }
660 660
661 661
662 662 /*
663 663 * Open FC port devctl node
664 664 */
665 665 static int
666 666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
667 667 {
668 668 int instance;
669 669 fc_local_port_t *port;
670 670
671 671 if (otype != OTYP_CHR) {
672 672 return (EINVAL);
673 673 }
674 674
675 675 /*
676 676 * This is not a toy to play with. Allow only powerful
677 677 * users (hopefully knowledgeable) to access the port
678 678 * (A hacker potentially could download a sick binary
679 679 * file into FCA)
680 680 */
681 681 if (drv_priv(credp)) {
682 682 return (EPERM);
683 683 }
684 684
685 685 instance = (int)getminor(*devp);
686 686
687 687 port = ddi_get_soft_state(fp_driver_softstate, instance);
688 688 if (port == NULL) {
689 689 return (ENXIO);
690 690 }
691 691
692 692 mutex_enter(&port->fp_mutex);
693 693 if (port->fp_flag & FP_EXCL) {
694 694 /*
695 695 * It is already open for exclusive access.
696 696 * So shut the door on this caller.
697 697 */
698 698 mutex_exit(&port->fp_mutex);
699 699 return (EBUSY);
700 700 }
701 701
702 702 if (flag & FEXCL) {
703 703 if (port->fp_flag & FP_OPEN) {
704 704 /*
705 705 * Exclusive operation not possible
706 706 * as it is already opened
707 707 */
708 708 mutex_exit(&port->fp_mutex);
709 709 return (EBUSY);
710 710 }
711 711 port->fp_flag |= FP_EXCL;
712 712 }
713 713 port->fp_flag |= FP_OPEN;
714 714 mutex_exit(&port->fp_mutex);
715 715
716 716 return (0);
717 717 }
718 718
719 719
720 720 /*
721 721 * The driver close entry point is called on the last close()
722 722 * of a device. So it is perfectly alright to just clobber the
723 723 * open flag and reset it to idle (instead of having to reset
724 724 * each flag bits). For any confusion, check out close(9E).
725 725 */
726 726
727 727 /* ARGSUSED */
728 728 static int
729 729 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
730 730 {
731 731 int instance;
732 732 fc_local_port_t *port;
733 733
734 734 if (otype != OTYP_CHR) {
735 735 return (EINVAL);
736 736 }
737 737
738 738 instance = (int)getminor(dev);
739 739
740 740 port = ddi_get_soft_state(fp_driver_softstate, instance);
741 741 if (port == NULL) {
742 742 return (ENXIO);
743 743 }
744 744
745 745 mutex_enter(&port->fp_mutex);
746 746 if ((port->fp_flag & FP_OPEN) == 0) {
747 747 mutex_exit(&port->fp_mutex);
748 748 return (ENODEV);
749 749 }
750 750 port->fp_flag = FP_IDLE;
751 751 mutex_exit(&port->fp_mutex);
752 752
753 753 return (0);
754 754 }
755 755
756 756 /*
757 757 * Handle IOCTL requests
758 758 */
759 759
760 760 /* ARGSUSED */
761 761 static int
762 762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
763 763 {
764 764 int instance;
765 765 int ret = 0;
766 766 fcio_t fcio;
767 767 fc_local_port_t *port;
768 768
769 769 instance = (int)getminor(dev);
770 770
771 771 port = ddi_get_soft_state(fp_driver_softstate, instance);
772 772 if (port == NULL) {
773 773 return (ENXIO);
774 774 }
775 775
776 776 mutex_enter(&port->fp_mutex);
777 777 if ((port->fp_flag & FP_OPEN) == 0) {
778 778 mutex_exit(&port->fp_mutex);
779 779 return (ENXIO);
780 780 }
781 781
782 782 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
783 783 mutex_exit(&port->fp_mutex);
784 784 return (ENXIO);
785 785 }
786 786
787 787 mutex_exit(&port->fp_mutex);
788 788
789 789 /* this will raise power if necessary */
790 790 ret = fctl_busy_port(port);
791 791 if (ret != 0) {
792 792 return (ret);
793 793 }
794 794
795 795 ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
796 796
797 797
798 798 switch (cmd) {
799 799 case FCIO_CMD: {
800 800 #ifdef _MULTI_DATAMODEL
801 801 switch (ddi_model_convert_from(mode & FMODELS)) {
802 802 case DDI_MODEL_ILP32: {
803 803 struct fcio32 fcio32;
804 804
805 805 if (ddi_copyin((void *)data, (void *)&fcio32,
806 806 sizeof (struct fcio32), mode)) {
807 807 ret = EFAULT;
808 808 break;
809 809 }
810 810 fcio.fcio_xfer = fcio32.fcio_xfer;
811 811 fcio.fcio_cmd = fcio32.fcio_cmd;
812 812 fcio.fcio_flags = fcio32.fcio_flags;
813 813 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
814 814 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
815 815 fcio.fcio_ibuf =
816 816 (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
817 817 fcio.fcio_olen = (size_t)fcio32.fcio_olen;
818 818 fcio.fcio_obuf =
819 819 (caddr_t)(uintptr_t)fcio32.fcio_obuf;
820 820 fcio.fcio_alen = (size_t)fcio32.fcio_alen;
821 821 fcio.fcio_abuf =
822 822 (caddr_t)(uintptr_t)fcio32.fcio_abuf;
823 823 fcio.fcio_errno = fcio32.fcio_errno;
824 824 break;
825 825 }
826 826
827 827 case DDI_MODEL_NONE:
828 828 if (ddi_copyin((void *)data, (void *)&fcio,
829 829 sizeof (fcio_t), mode)) {
830 830 ret = EFAULT;
831 831 }
832 832 break;
833 833 }
834 834 #else /* _MULTI_DATAMODEL */
835 835 if (ddi_copyin((void *)data, (void *)&fcio,
836 836 sizeof (fcio_t), mode)) {
837 837 ret = EFAULT;
838 838 break;
839 839 }
840 840 #endif /* _MULTI_DATAMODEL */
841 841 if (!ret) {
842 842 ret = fp_fciocmd(port, data, mode, &fcio);
843 843 }
844 844 break;
845 845 }
846 846
847 847 default:
848 848 ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
849 849 mode, credp, rval);
850 850 }
851 851
852 852 fctl_idle_port(port);
853 853
854 854 return (ret);
855 855 }
856 856
857 857
858 858 /*
859 859 * Init Symbolic Port Name and Node Name
860 860 * LV will try to get symbolic names from FCA driver
861 861 * and register these to name server,
862 862 * if LV fails to get these,
863 863 * LV will register its default symbolic names to name server.
864 864 * The Default symbolic node name format is :
865 865 * <hostname>:<hba driver name>(instance)
866 866 * The Default symbolic port name format is :
867 867 * <fp path name>
868 868 */
869 869 static void
870 870 fp_init_symbolic_names(fc_local_port_t *port)
871 871 {
872 872 const char *vendorname = ddi_driver_name(port->fp_fca_dip);
873 873 char *sym_name;
874 874 char fcaname[50] = {0};
875 875 int hostnlen, fcanlen;
876 876
877 877 if (port->fp_sym_node_namelen == 0) {
878 878 hostnlen = strlen(utsname.nodename);
879 879 (void) snprintf(fcaname, sizeof (fcaname),
880 880 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
881 881 fcanlen = strlen(fcaname);
882 882
883 883 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
884 884 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
885 885 port->fp_sym_node_namelen = strlen(sym_name);
886 886 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
887 887 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
888 888 }
889 889 (void) strncpy(port->fp_sym_node_name, sym_name,
890 890 port->fp_sym_node_namelen);
891 891 kmem_free(sym_name, hostnlen + fcanlen + 2);
892 892 }
893 893
894 894 if (port->fp_sym_port_namelen == 0) {
895 895 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
896 896
897 897 (void) ddi_pathname(port->fp_port_dip, pathname);
898 898 port->fp_sym_port_namelen = strlen(pathname);
899 899 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
900 900 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
901 901 }
902 902 (void) strncpy(port->fp_sym_port_name, pathname,
903 903 port->fp_sym_port_namelen);
904 904 kmem_free(pathname, MAXPATHLEN);
905 905 }
906 906 }
907 907
908 908
909 909 /*
910 910 * Perform port attach
911 911 */
912 912 static int
913 913 fp_attach_handler(dev_info_t *dip)
914 914 {
915 915 int rval;
916 916 int instance;
917 917 int port_num;
918 918 int port_len;
919 919 char name[30];
920 920 char i_pwwn[17];
921 921 fp_cmd_t *pkt;
922 922 uint32_t ub_count;
923 923 fc_local_port_t *port;
924 924 job_request_t *job;
925 925 fc_local_port_t *phyport = NULL;
926 926 int portpro1;
927 927 char pwwn[17], nwwn[17];
928 928
929 929 instance = ddi_get_instance(dip);
930 930 port_len = sizeof (port_num);
931 931 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
932 932 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
933 933 (caddr_t)&port_num, &port_len);
934 934 if (rval != DDI_SUCCESS) {
935 935 cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
936 936 instance);
937 937 return (DDI_FAILURE);
938 938 }
939 939
940 940 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
941 941 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
942 942 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
943 943 instance);
944 944 return (DDI_FAILURE);
945 945 }
946 946
947 947 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
948 948 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
949 949 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
950 950 " point minor node", instance);
951 951 ddi_remove_minor_node(dip, NULL);
952 952 return (DDI_FAILURE);
953 953 }
954 954
955 955 if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
956 956 != DDI_SUCCESS) {
957 957 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
958 958 instance);
959 959 ddi_remove_minor_node(dip, NULL);
960 960 return (DDI_FAILURE);
961 961 }
962 962 port = ddi_get_soft_state(fp_driver_softstate, instance);
963 963
964 964 (void) sprintf(port->fp_ibuf, "fp(%d)", instance);
965 965
966 966 port->fp_instance = instance;
967 967 port->fp_ulp_attach = 1;
968 968 port->fp_port_num = port_num;
969 969 port->fp_verbose = fp_verbosity;
970 970 port->fp_options = fp_options;
971 971
972 972 port->fp_fca_dip = ddi_get_parent(dip);
973 973 port->fp_port_dip = dip;
974 974 port->fp_fca_tran = (fc_fca_tran_t *)
975 975 ddi_get_driver_private(port->fp_fca_dip);
976 976
977 977 port->fp_task = port->fp_last_task = FP_TASK_IDLE;
978 978
979 979 /*
980 980 * Init the starting value of fp_rscn_count. Note that if
981 981 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
982 982 * actual # of RSCNs will be (fp_rscn_count - 1)
983 983 */
984 984 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
985 985
986 986 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
987 987 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
988 988 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
989 989
990 990 (void) sprintf(name, "fp%d_cache", instance);
991 991
992 992 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
993 993 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
994 994 "phyport-instance", -1)) != -1) {
995 995 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
996 996 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
997 997 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
998 998 port->fp_npiv_type = FC_NPIV_PORT;
999 999 }
1000 1000
1001 1001 /*
1002 1002 * Allocate the pool of fc_packet_t structs to be used with
1003 1003 * this fp instance.
1004 1004 */
1005 1005 port->fp_pkt_cache = kmem_cache_create(name,
1006 1006 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1007 1007 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1008 1008 NULL, 0);
1009 1009 port->fp_out_fpcmds = 0;
1010 1010 if (port->fp_pkt_cache == NULL) {
1011 1011 goto cache_alloc_failed;
1012 1012 }
1013 1013
1014 1014
1015 1015 /*
1016 1016 * Allocate the d_id and pwwn hash tables for all remote ports
1017 1017 * connected to this local port.
1018 1018 */
1019 1019 port->fp_did_table = kmem_zalloc(did_table_size *
1020 1020 sizeof (struct d_id_hash), KM_SLEEP);
1021 1021
1022 1022 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1023 1023 sizeof (struct pwwn_hash), KM_SLEEP);
1024 1024
1025 1025 port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1026 1026 MINCLSYSPRI, 1, 16, 0);
1027 1027
1028 1028 /* Indicate that don't have the pm components yet */
1029 1029 port->fp_soft_state |= FP_SOFT_NO_PMCOMP;
1030 1030
1031 1031 /*
1032 1032 * Bind the callbacks with the FCA driver. This will open the gate
1033 1033 * for asynchronous callbacks, so after this call the fp_mutex
1034 1034 * must be held when updating the fc_local_port_t struct.
1035 1035 *
1036 1036 * This is done _before_ setting up the job thread so we can avoid
1037 1037 * cleaning up after the thread_create() in the error path. This
1038 1038 * also means fp will be operating with fp_els_resp_pkt set to NULL.
1039 1039 */
1040 1040 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1041 1041 goto bind_callbacks_failed;
1042 1042 }
1043 1043
1044 1044 if (phyport) {
1045 1045 mutex_enter(&phyport->fp_mutex);
1046 1046 if (phyport->fp_port_next) {
1047 1047 phyport->fp_port_next->fp_port_prev = port;
1048 1048 port->fp_port_next = phyport->fp_port_next;
1049 1049 phyport->fp_port_next = port;
1050 1050 port->fp_port_prev = phyport;
1051 1051 } else {
1052 1052 phyport->fp_port_next = port;
1053 1053 phyport->fp_port_prev = port;
1054 1054 port->fp_port_next = phyport;
1055 1055 port->fp_port_prev = phyport;
1056 1056 }
1057 1057 mutex_exit(&phyport->fp_mutex);
1058 1058 }
1059 1059
1060 1060 /*
1061 1061 * Init Symbolic Names
1062 1062 */
1063 1063 fp_init_symbolic_names(port);
1064 1064
1065 1065 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1066 1066 KM_SLEEP, NULL);
1067 1067
1068 1068 if (pkt == NULL) {
1069 1069 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1070 1070 instance);
1071 1071 goto alloc_els_packet_failed;
1072 1072 }
1073 1073
1074 1074 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1075 1075 v.v_maxsyspri - 2);
1076 1076
1077 1077 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1078 1078 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1079 1079 i_pwwn) != DDI_PROP_SUCCESS) {
1080 1080 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1081 1081 "fp(%d): Updating 'initiator-port' property"
1082 1082 " on fp dev_info node failed", instance);
1083 1083 }
1084 1084
1085 1085 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1086 1086 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1087 1087 i_pwwn) != DDI_PROP_SUCCESS) {
1088 1088 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1089 1089 "fp(%d): Updating 'initiator-node' property"
1090 1090 " on fp dev_info node failed", instance);
1091 1091 }
1092 1092
1093 1093 mutex_enter(&port->fp_mutex);
1094 1094 port->fp_els_resp_pkt = pkt;
1095 1095 mutex_exit(&port->fp_mutex);
1096 1096
1097 1097 /*
1098 1098 * Determine the count of unsolicited buffers this FCA can support
1099 1099 */
1100 1100 fp_retrieve_caps(port);
1101 1101
1102 1102 /*
1103 1103 * Allocate unsolicited buffer tokens
1104 1104 */
1105 1105 if (port->fp_ub_count) {
1106 1106 ub_count = port->fp_ub_count;
1107 1107 port->fp_ub_tokens = kmem_zalloc(ub_count *
1108 1108 sizeof (*port->fp_ub_tokens), KM_SLEEP);
1109 1109 /*
1110 1110 * Do not fail the attach if unsolicited buffer allocation
1111 1111 * fails; Just try to get along with whatever the FCA can do.
1112 1112 */
1113 1113 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1114 1114 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1115 1115 FC_SUCCESS || ub_count != port->fp_ub_count) {
1116 1116 cmn_err(CE_WARN, "fp(%d): failed to allocate "
1117 1117 " Unsolicited buffers. proceeding with attach...",
1118 1118 instance);
1119 1119 kmem_free(port->fp_ub_tokens,
1120 1120 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1121 1121 port->fp_ub_tokens = NULL;
1122 1122 }
1123 1123 }
1124 1124
1125 1125 fp_load_ulp_modules(dip, port);
1126 1126
1127 1127 /*
1128 1128 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1129 1129 */
1130 1130 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1131 1131 "pm-hardware-state", "needs-suspend-resume",
1132 1132 strlen("needs-suspend-resume") + 1);
1133 1133
1134 1134 /*
1135 1135 * fctl maintains a list of all port handles, so
1136 1136 * help fctl add this one to its list now.
1137 1137 */
1138 1138 mutex_enter(&port->fp_mutex);
1139 1139 fctl_add_port(port);
1140 1140
1141 1141 /*
1142 1142 * If a state change is already in progress, set the bind state t
1143 1143 * OFFLINE as well, so further state change callbacks into ULPs
1144 1144 * will pass the appropriate states
1145 1145 */
1146 1146 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1147 1147 port->fp_statec_busy) {
1148 1148 port->fp_bind_state = FC_STATE_OFFLINE;
1149 1149 mutex_exit(&port->fp_mutex);
1150 1150
1151 1151 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1152 1152 } else {
1153 1153 /*
1154 1154 * Without dropping the mutex, ensure that the port
1155 1155 * startup happens ahead of state change callback
1156 1156 * processing
1157 1157 */
1158 1158 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1159 1159
1160 1160 port->fp_last_task = port->fp_task;
1161 1161 port->fp_task = FP_TASK_PORT_STARTUP;
1162 1162
1163 1163 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1164 1164 fp_startup_done, (opaque_t)port, KM_SLEEP);
1165 1165
1166 1166 port->fp_job_head = port->fp_job_tail = job;
1167 1167
1168 1168 cv_signal(&port->fp_cv);
1169 1169
1170 1170 mutex_exit(&port->fp_mutex);
1171 1171 }
1172 1172
1173 1173 mutex_enter(&port->fp_mutex);
1174 1174 while (port->fp_ulp_attach) {
1175 1175 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1176 1176 }
1177 1177 mutex_exit(&port->fp_mutex);
1178 1178
1179 1179 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1180 1180 "pm-components", fp_pm_comps,
1181 1181 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1182 1182 DDI_PROP_SUCCESS) {
1183 1183 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1184 1184 " components property, PM disabled on this port.");
1185 1185 mutex_enter(&port->fp_mutex);
1186 1186 port->fp_pm_level = FP_PM_PORT_UP;
1187 1187 mutex_exit(&port->fp_mutex);
1188 1188 } else {
1189 1189 if (pm_raise_power(dip, FP_PM_COMPONENT,
1190 1190 FP_PM_PORT_UP) != DDI_SUCCESS) {
1191 1191 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1192 1192 " power level");
1193 1193 mutex_enter(&port->fp_mutex);
1194 1194 port->fp_pm_level = FP_PM_PORT_UP;
1195 1195 mutex_exit(&port->fp_mutex);
1196 1196 }
1197 1197
1198 1198 /*
1199 1199 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1200 1200 * the call to pm_raise_power. The PM framework can't
1201 1201 * handle multiple threads calling into it during attach.
1202 1202 */
1203 1203
1204 1204 mutex_enter(&port->fp_mutex);
1205 1205 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP;
1206 1206 mutex_exit(&port->fp_mutex);
1207 1207 }
1208 1208
1209 1209 ddi_report_dev(dip);
1210 1210
1211 1211 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1212 1212
1213 1213 return (DDI_SUCCESS);
1214 1214
1215 1215 /*
1216 1216 * Unwind any/all preceeding allocations in the event of an error.
1217 1217 */
1218 1218
1219 1219 alloc_els_packet_failed:
1220 1220
1221 1221 if (port->fp_fca_handle != NULL) {
1222 1222 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1223 1223 port->fp_fca_handle = NULL;
1224 1224 }
1225 1225
1226 1226 if (port->fp_ub_tokens != NULL) {
1227 1227 (void) fc_ulp_ubfree(port, port->fp_ub_count,
1228 1228 port->fp_ub_tokens);
1229 1229 kmem_free(port->fp_ub_tokens,
1230 1230 port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1231 1231 port->fp_ub_tokens = NULL;
1232 1232 }
1233 1233
1234 1234 if (port->fp_els_resp_pkt != NULL) {
1235 1235 fp_free_pkt(port->fp_els_resp_pkt);
1236 1236 port->fp_els_resp_pkt = NULL;
1237 1237 }
1238 1238
1239 1239 bind_callbacks_failed:
1240 1240
1241 1241 if (port->fp_taskq != NULL) {
1242 1242 taskq_destroy(port->fp_taskq);
1243 1243 }
1244 1244
1245 1245 if (port->fp_pwwn_table != NULL) {
1246 1246 kmem_free(port->fp_pwwn_table,
1247 1247 pwwn_table_size * sizeof (struct pwwn_hash));
1248 1248 port->fp_pwwn_table = NULL;
1249 1249 }
1250 1250
1251 1251 if (port->fp_did_table != NULL) {
1252 1252 kmem_free(port->fp_did_table,
1253 1253 did_table_size * sizeof (struct d_id_hash));
1254 1254 port->fp_did_table = NULL;
1255 1255 }
1256 1256
1257 1257 if (port->fp_pkt_cache != NULL) {
1258 1258 kmem_cache_destroy(port->fp_pkt_cache);
1259 1259 port->fp_pkt_cache = NULL;
1260 1260 }
1261 1261
1262 1262 cache_alloc_failed:
1263 1263
1264 1264 cv_destroy(&port->fp_attach_cv);
1265 1265 cv_destroy(&port->fp_cv);
1266 1266 mutex_destroy(&port->fp_mutex);
1267 1267 ddi_remove_minor_node(port->fp_port_dip, NULL);
1268 1268 ddi_soft_state_free(fp_driver_softstate, instance);
1269 1269 ddi_prop_remove_all(dip);
1270 1270
1271 1271 return (DDI_FAILURE);
1272 1272 }
1273 1273
1274 1274
1275 1275 /*
1276 1276 * Handle DDI_RESUME request
1277 1277 */
1278 1278 static int
1279 1279 fp_resume_handler(dev_info_t *dip)
1280 1280 {
1281 1281 int rval;
1282 1282 fc_local_port_t *port;
1283 1283
1284 1284 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1285 1285
1286 1286 ASSERT(port != NULL);
1287 1287
1288 1288 #ifdef DEBUG
1289 1289 mutex_enter(&port->fp_mutex);
1290 1290 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1291 1291 mutex_exit(&port->fp_mutex);
1292 1292 #endif
1293 1293
1294 1294 /*
1295 1295 * If the port was power suspended, raise the power level
1296 1296 */
1297 1297 mutex_enter(&port->fp_mutex);
1298 1298 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1299 1299 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1300 1300 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1301 1301
1302 1302 mutex_exit(&port->fp_mutex);
1303 1303 if (pm_raise_power(dip, FP_PM_COMPONENT,
1304 1304 FP_PM_PORT_UP) != DDI_SUCCESS) {
1305 1305 FP_TRACE(FP_NHEAD2(9, 0),
1306 1306 "Failed to raise the power level");
1307 1307 return (DDI_FAILURE);
1308 1308 }
1309 1309 mutex_enter(&port->fp_mutex);
1310 1310 }
1311 1311 port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1312 1312 mutex_exit(&port->fp_mutex);
1313 1313
1314 1314 /*
1315 1315 * All the discovery is initiated and handled by per-port thread.
1316 1316 * Further all the discovery is done in handled in callback mode
1317 1317 * (not polled mode); In a specific case such as this, the discovery
1318 1318 * is required to happen in polled mode. The easiest way out is
1319 1319 * to bail out port thread and get started. Come back and fix this
1320 1320 * to do on demand discovery initiated by ULPs. ULPs such as FCP
1321 1321 * will do on-demand discovery during pre-power-up busctl handling
1322 1322 * which will only be possible when SCSA provides a new HBA vector
1323 1323 * for sending down the PM busctl requests.
1324 1324 */
1325 1325 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1326 1326
1327 1327 rval = fp_resume_all(port, FC_CMD_RESUME);
1328 1328 if (rval != DDI_SUCCESS) {
1329 1329 mutex_enter(&port->fp_mutex);
1330 1330 port->fp_soft_state |= FP_SOFT_SUSPEND;
1331 1331 mutex_exit(&port->fp_mutex);
1332 1332 (void) callb_generic_cpr(&port->fp_cpr_info,
1333 1333 CB_CODE_CPR_CHKPT);
1334 1334 }
1335 1335
1336 1336 return (rval);
1337 1337 }
1338 1338
1339 1339 /*
1340 1340 * Perform FC Port power on initialization
1341 1341 */
1342 1342 static int
1343 1343 fp_power_up(fc_local_port_t *port)
1344 1344 {
1345 1345 int rval;
1346 1346
1347 1347 ASSERT(MUTEX_HELD(&port->fp_mutex));
1348 1348
1349 1349 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1350 1350 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1351 1351
1352 1352 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1353 1353
1354 1354 mutex_exit(&port->fp_mutex);
1355 1355
1356 1356 rval = fp_resume_all(port, FC_CMD_POWER_UP);
1357 1357 if (rval != DDI_SUCCESS) {
1358 1358 mutex_enter(&port->fp_mutex);
1359 1359 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1360 1360 } else {
1361 1361 mutex_enter(&port->fp_mutex);
1362 1362 }
1363 1363
1364 1364 return (rval);
1365 1365 }
1366 1366
1367 1367
1368 1368 /*
1369 1369 * It is important to note that the power may possibly be removed between
1370 1370 * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1371 1371 * FC port hardware would have gone through an OFFLINE to ONLINE transition
1372 1372 * (hardware state). In this case, the port driver may need to rediscover the
1373 1373 * topology, perform LOGINs, register with the name server again and perform
1374 1374 * any such port initialization procedures. To perform LOGINs, the driver could
1375 1375 * use the port device handle to see if a LOGIN needs to be performed and use
1376 1376 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1377 1377 * or removed) which will be reflected in the map the ULPs will see.
1378 1378 */
1379 1379 static int
1380 1380 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1381 1381 {
1382 1382
1383 1383 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1384 1384
1385 1385 if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1386 1386 return (DDI_FAILURE);
1387 1387 }
1388 1388
1389 1389 mutex_enter(&port->fp_mutex);
1390 1390
1391 1391 /*
1392 1392 * If there are commands queued for delayed retry, instead of
1393 1393 * working the hard way to figure out which ones are good for
1394 1394 * restart and which ones not (ELSs are definitely not good
1395 1395 * as the port will have to go through a new spin of rediscovery
1396 1396 * now), so just flush them out.
1397 1397 */
1398 1398 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1399 1399 fp_cmd_t *cmd;
1400 1400
1401 1401 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1402 1402
1403 1403 mutex_exit(&port->fp_mutex);
1404 1404 while ((cmd = fp_deque_cmd(port)) != NULL) {
1405 1405 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1406 1406 fp_iodone(cmd);
1407 1407 }
1408 1408 mutex_enter(&port->fp_mutex);
1409 1409 }
1410 1410
1411 1411 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1412 1412 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1413 1413 port->fp_dev_count) {
1414 1414 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1415 1415 port->fp_offline_tid = timeout(fp_offline_timeout,
1416 1416 (caddr_t)port, fp_offline_ticks);
1417 1417 }
1418 1418 if (port->fp_job_head) {
1419 1419 cv_signal(&port->fp_cv);
1420 1420 }
1421 1421 mutex_exit(&port->fp_mutex);
1422 1422 fctl_attach_ulps(port, cmd, &modlinkage);
1423 1423 } else {
1424 1424 struct job_request *job;
1425 1425
1426 1426 /*
1427 1427 * If an OFFLINE timer was running at the time of
1428 1428 * suspending, there is no need to restart it as
1429 1429 * the port is ONLINE now.
1430 1430 */
1431 1431 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1432 1432 if (port->fp_statec_busy == 0) {
1433 1433 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1434 1434 }
1435 1435 port->fp_statec_busy++;
1436 1436 mutex_exit(&port->fp_mutex);
1437 1437
1438 1438 job = fctl_alloc_job(JOB_PORT_ONLINE,
1439 1439 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1440 1440 fctl_enque_job(port, job);
1441 1441
1442 1442 fctl_jobwait(job);
1443 1443 fctl_remove_oldies(port);
1444 1444
1445 1445 fctl_attach_ulps(port, cmd, &modlinkage);
1446 1446 fctl_dealloc_job(job);
1447 1447 }
1448 1448
1449 1449 return (DDI_SUCCESS);
1450 1450 }
1451 1451
1452 1452
1453 1453 /*
1454 1454 * At this time, there shouldn't be any I/O requests on this port.
1455 1455 * But the unsolicited callbacks from the underlying FCA port need
1456 1456 * to be handled very carefully. The steps followed to handle the
1457 1457 * DDI_DETACH are:
1458 1458 * + Grab the port driver mutex, check if the unsolicited
1459 1459 * callback is currently under processing. If true, fail
1460 1460 * the DDI_DETACH request by printing a message; If false
1461 1461 * mark the DDI_DETACH as under progress, so that any
1462 1462 * further unsolicited callbacks get bounced.
1463 1463 * + Perform PRLO/LOGO if necessary, cleanup all the data
1464 1464 * structures.
1465 1465 * + Get the job_handler thread to gracefully exit.
1466 1466 * + Unregister callbacks with the FCA port.
1467 1467 * + Now that some peace is found, notify all the ULPs of
1468 1468 * DDI_DETACH request (using ulp_port_detach entry point)
1469 1469 * + Free all mutexes, semaphores, conditional variables.
1470 1470 * + Free the soft state, return success.
1471 1471 *
1472 1472 * Important considerations:
1473 1473 * Port driver de-registers state change and unsolicited
1474 1474 * callbacks before taking up the task of notifying ULPs
1475 1475 * and performing PRLO and LOGOs.
1476 1476 *
1477 1477 * A port may go offline at the time PRLO/LOGO is being
1478 1478 * requested. It is expected of all FCA drivers to fail
1479 1479 * such requests either immediately with a FC_OFFLINE
1480 1480 * return code to fc_fca_transport() or return the packet
1481 1481 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1482 1482 */
1483 1483 static int
1484 1484 fp_detach_handler(fc_local_port_t *port)
1485 1485 {
1486 1486 job_request_t *job;
1487 1487 uint32_t delay_count;
1488 1488 fc_orphan_t *orp, *tmporp;
1489 1489
1490 1490 /*
1491 1491 * In a Fabric topology with many host ports connected to
1492 1492 * a switch, another detaching instance of fp might have
1493 1493 * triggered a LOGO (which is an unsolicited request to
1494 1494 * this instance). So in order to be able to successfully
1495 1495 * detach by taking care of such cases a delay of about
1496 1496 * 30 seconds is introduced.
1497 1497 */
1498 1498 delay_count = 0;
1499 1499 mutex_enter(&port->fp_mutex);
1500 1500 if (port->fp_out_fpcmds != 0) {
1501 1501 /*
1502 1502 * At this time we can only check fp internal commands, because
1503 1503 * sd/ssd/scsi_vhci should have finsihed all their commands,
1504 1504 * fcp/fcip/fcsm should have finished all their commands.
1505 1505 *
1506 1506 * It seems that all fp internal commands are asynchronous now.
1507 1507 */
1508 1508 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1509 1509 mutex_exit(&port->fp_mutex);
1510 1510
↓ open down ↓ |
1059 lines elided |
↑ open up ↑ |
1511 1511 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
1512 1512 " Failing detach", port->fp_instance, port->fp_out_fpcmds);
1513 1513 return (DDI_FAILURE);
1514 1514 }
1515 1515
1516 1516 while ((port->fp_soft_state &
1517 1517 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1518 1518 (delay_count < 30)) {
1519 1519 mutex_exit(&port->fp_mutex);
1520 1520 delay_count++;
1521 - delay(drv_usectohz(1000000));
1521 + delay(drv_sectohz(1));
1522 1522 mutex_enter(&port->fp_mutex);
1523 1523 }
1524 1524
1525 1525 if (port->fp_soft_state &
1526 1526 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1527 1527 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1528 1528 mutex_exit(&port->fp_mutex);
1529 1529
1530 1530 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1531 1531 " Failing detach", port->fp_instance);
1532 1532 return (DDI_FAILURE);
1533 1533 }
1534 1534
1535 1535 port->fp_soft_state |= FP_SOFT_IN_DETACH;
1536 1536 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1537 1537 mutex_exit(&port->fp_mutex);
1538 1538
1539 1539 /*
1540 1540 * If we're powered down, we need to raise power prior to submitting
1541 1541 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never
1542 1542 * process the shutdown job.
1543 1543 */
1544 1544 if (fctl_busy_port(port) != 0) {
1545 1545 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1546 1546 port->fp_instance);
1547 1547 mutex_enter(&port->fp_mutex);
1548 1548 port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1549 1549 mutex_exit(&port->fp_mutex);
1550 1550 return (DDI_FAILURE);
1551 1551 }
1552 1552
1553 1553 /*
1554 1554 * This will deallocate data structs and cause the "job" thread
1555 1555 * to exit, in preparation for DDI_DETACH on the instance.
1556 1556 * This can sleep for an arbitrary duration, since it waits for
1557 1557 * commands over the wire, timeout(9F) callbacks, etc.
1558 1558 *
1559 1559 * CAUTION: There is still a race here, where the "job" thread
1560 1560 * can still be executing code even tho the fctl_jobwait() call
1561 1561 * below has returned to us. In theory the fp driver could even be
1562 1562 * modunloaded even tho the job thread isn't done executing.
1563 1563 * without creating the race condition.
1564 1564 */
1565 1565 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1566 1566 (opaque_t)port, KM_SLEEP);
1567 1567 fctl_enque_job(port, job);
1568 1568 fctl_jobwait(job);
1569 1569 fctl_dealloc_job(job);
1570 1570
1571 1571
1572 1572 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1573 1573 FP_PM_PORT_DOWN);
1574 1574
1575 1575 if (port->fp_taskq) {
1576 1576 taskq_destroy(port->fp_taskq);
1577 1577 }
1578 1578
1579 1579 ddi_prop_remove_all(port->fp_port_dip);
1580 1580
1581 1581 ddi_remove_minor_node(port->fp_port_dip, NULL);
1582 1582
1583 1583 fctl_remove_port(port);
1584 1584
1585 1585 fp_free_pkt(port->fp_els_resp_pkt);
1586 1586
1587 1587 if (port->fp_ub_tokens) {
1588 1588 if (fc_ulp_ubfree(port, port->fp_ub_count,
1589 1589 port->fp_ub_tokens) != FC_SUCCESS) {
1590 1590 cmn_err(CE_WARN, "fp(%d): couldn't free "
1591 1591 " unsolicited buffers", port->fp_instance);
1592 1592 }
1593 1593 kmem_free(port->fp_ub_tokens,
1594 1594 sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1595 1595 port->fp_ub_tokens = NULL;
1596 1596 }
1597 1597
1598 1598 if (port->fp_pkt_cache != NULL) {
1599 1599 kmem_cache_destroy(port->fp_pkt_cache);
1600 1600 }
1601 1601
1602 1602 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1603 1603
1604 1604 mutex_enter(&port->fp_mutex);
1605 1605 if (port->fp_did_table) {
1606 1606 kmem_free(port->fp_did_table, did_table_size *
1607 1607 sizeof (struct d_id_hash));
1608 1608 }
1609 1609
1610 1610 if (port->fp_pwwn_table) {
1611 1611 kmem_free(port->fp_pwwn_table, pwwn_table_size *
1612 1612 sizeof (struct pwwn_hash));
1613 1613 }
1614 1614 orp = port->fp_orphan_list;
1615 1615 while (orp) {
1616 1616 tmporp = orp;
1617 1617 orp = orp->orp_next;
1618 1618 kmem_free(tmporp, sizeof (*orp));
1619 1619 }
1620 1620
1621 1621 mutex_exit(&port->fp_mutex);
1622 1622
1623 1623 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1624 1624
1625 1625 mutex_destroy(&port->fp_mutex);
1626 1626 cv_destroy(&port->fp_attach_cv);
1627 1627 cv_destroy(&port->fp_cv);
1628 1628 ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1629 1629
1630 1630 return (DDI_SUCCESS);
1631 1631 }
1632 1632
1633 1633
1634 1634 /*
1635 1635 * Steps to perform DDI_SUSPEND operation on a FC port
1636 1636 *
1637 1637 * - If already suspended return DDI_FAILURE
1638 1638 * - If already power-suspended return DDI_SUCCESS
1639 1639 * - If an unsolicited callback or state change handling is in
1640 1640 * in progress, throw a warning message, return DDI_FAILURE
1641 1641 * - Cancel timeouts
1642 1642 * - SUSPEND the job_handler thread (means do nothing as it is
1643 1643 * taken care of by the CPR frame work)
1644 1644 */
1645 1645 static int
1646 1646 fp_suspend_handler(fc_local_port_t *port)
1647 1647 {
1648 1648 uint32_t delay_count;
1649 1649
1650 1650 mutex_enter(&port->fp_mutex);
1651 1651
1652 1652 /*
1653 1653 * The following should never happen, but
1654 1654 * let the driver be more defensive here
1655 1655 */
1656 1656 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1657 1657 mutex_exit(&port->fp_mutex);
1658 1658 return (DDI_FAILURE);
1659 1659 }
1660 1660
1661 1661 /*
1662 1662 * If the port is already power suspended, there
1663 1663 * is nothing else to do, So return DDI_SUCCESS,
1664 1664 * but mark the SUSPEND bit in the soft state
1665 1665 * before leaving.
1666 1666 */
1667 1667 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1668 1668 port->fp_soft_state |= FP_SOFT_SUSPEND;
1669 1669 mutex_exit(&port->fp_mutex);
1670 1670 return (DDI_SUCCESS);
1671 1671 }
1672 1672
1673 1673 /*
1674 1674 * Check if an unsolicited callback or state change handling is
1675 1675 * in progress. If true, fail the suspend operation; also throw
1676 1676 * a warning message notifying the failure. Note that Sun PCI
1677 1677 * hotplug spec recommends messages in cases of failure (but
1678 1678 * not flooding the console)
1679 1679 *
1680 1680 * Busy waiting for a short interval (500 millisecond ?) to see
↓ open down ↓ |
149 lines elided |
↑ open up ↑ |
1681 1681 * if the callback processing completes may be another idea. Since
1682 1682 * most of the callback processing involves a lot of work, it
1683 1683 * is safe to just fail the SUSPEND operation. It is definitely
1684 1684 * not bad to fail the SUSPEND operation if the driver is busy.
1685 1685 */
1686 1686 delay_count = 0;
1687 1687 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1688 1688 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1689 1689 mutex_exit(&port->fp_mutex);
1690 1690 delay_count++;
1691 - delay(drv_usectohz(1000000));
1691 + delay(drv_sectohz(1));
1692 1692 mutex_enter(&port->fp_mutex);
1693 1693 }
1694 1694
1695 1695 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1696 1696 FP_SOFT_IN_UNSOL_CB)) {
1697 1697 mutex_exit(&port->fp_mutex);
1698 1698 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1699 1699 " Failing suspend", port->fp_instance);
1700 1700 return (DDI_FAILURE);
1701 1701 }
1702 1702
1703 1703 /*
1704 1704 * Check of FC port thread is busy
1705 1705 */
1706 1706 if (port->fp_job_head) {
1707 1707 mutex_exit(&port->fp_mutex);
1708 1708 FP_TRACE(FP_NHEAD2(9, 0),
1709 1709 "FC port thread is busy: Failing suspend");
1710 1710 return (DDI_FAILURE);
1711 1711 }
1712 1712 port->fp_soft_state |= FP_SOFT_SUSPEND;
1713 1713
1714 1714 fp_suspend_all(port);
1715 1715 mutex_exit(&port->fp_mutex);
1716 1716
1717 1717 return (DDI_SUCCESS);
1718 1718 }
1719 1719
1720 1720
1721 1721 /*
1722 1722 * Prepare for graceful power down of a FC port
1723 1723 */
1724 1724 static int
1725 1725 fp_power_down(fc_local_port_t *port)
1726 1726 {
1727 1727 ASSERT(MUTEX_HELD(&port->fp_mutex));
1728 1728
1729 1729 /*
1730 1730 * Power down request followed by a DDI_SUSPEND should
1731 1731 * never happen; If it does return DDI_SUCCESS
1732 1732 */
1733 1733 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1734 1734 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1735 1735 return (DDI_SUCCESS);
1736 1736 }
1737 1737
1738 1738 /*
1739 1739 * If the port is already power suspended, there
1740 1740 * is nothing else to do, So return DDI_SUCCESS,
1741 1741 */
1742 1742 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1743 1743 return (DDI_SUCCESS);
1744 1744 }
1745 1745
1746 1746 /*
1747 1747 * Check if an unsolicited callback or state change handling
1748 1748 * is in progress. If true, fail the PM suspend operation.
1749 1749 * But don't print a message unless the verbosity of the
1750 1750 * driver desires otherwise.
1751 1751 */
1752 1752 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1753 1753 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1754 1754 FP_TRACE(FP_NHEAD2(9, 0),
1755 1755 "Unsolicited callback in progress: Failing power down");
1756 1756 return (DDI_FAILURE);
1757 1757 }
1758 1758
1759 1759 /*
1760 1760 * Check of FC port thread is busy
1761 1761 */
1762 1762 if (port->fp_job_head) {
1763 1763 FP_TRACE(FP_NHEAD2(9, 0),
1764 1764 "FC port thread is busy: Failing power down");
1765 1765 return (DDI_FAILURE);
1766 1766 }
1767 1767 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1768 1768
1769 1769 /*
1770 1770 * check if the ULPs are ready for power down
1771 1771 */
1772 1772 mutex_exit(&port->fp_mutex);
1773 1773 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1774 1774 &modlinkage) != FC_SUCCESS) {
1775 1775 mutex_enter(&port->fp_mutex);
1776 1776 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1777 1777 mutex_exit(&port->fp_mutex);
1778 1778
1779 1779 /*
1780 1780 * Power back up the obedient ULPs that went down
1781 1781 */
1782 1782 fp_attach_ulps(port, FC_CMD_POWER_UP);
1783 1783
1784 1784 FP_TRACE(FP_NHEAD2(9, 0),
1785 1785 "ULP(s) busy, detach_ulps failed. Failing power down");
1786 1786 mutex_enter(&port->fp_mutex);
1787 1787 return (DDI_FAILURE);
1788 1788 }
1789 1789 mutex_enter(&port->fp_mutex);
1790 1790
1791 1791 fp_suspend_all(port);
1792 1792
1793 1793 return (DDI_SUCCESS);
1794 1794 }
1795 1795
1796 1796
1797 1797 /*
1798 1798 * Suspend the entire FC port
1799 1799 */
1800 1800 static void
1801 1801 fp_suspend_all(fc_local_port_t *port)
1802 1802 {
1803 1803 int index;
1804 1804 struct pwwn_hash *head;
1805 1805 fc_remote_port_t *pd;
1806 1806
1807 1807 ASSERT(MUTEX_HELD(&port->fp_mutex));
1808 1808
1809 1809 if (port->fp_wait_tid != 0) {
1810 1810 timeout_id_t tid;
1811 1811
1812 1812 tid = port->fp_wait_tid;
1813 1813 port->fp_wait_tid = (timeout_id_t)NULL;
1814 1814 mutex_exit(&port->fp_mutex);
1815 1815 (void) untimeout(tid);
1816 1816 mutex_enter(&port->fp_mutex);
1817 1817 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1818 1818 }
1819 1819
1820 1820 if (port->fp_offline_tid) {
1821 1821 timeout_id_t tid;
1822 1822
1823 1823 tid = port->fp_offline_tid;
1824 1824 port->fp_offline_tid = (timeout_id_t)NULL;
1825 1825 mutex_exit(&port->fp_mutex);
1826 1826 (void) untimeout(tid);
1827 1827 mutex_enter(&port->fp_mutex);
1828 1828 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1829 1829 }
1830 1830 mutex_exit(&port->fp_mutex);
1831 1831 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1832 1832 mutex_enter(&port->fp_mutex);
1833 1833
1834 1834 /*
1835 1835 * Mark all devices as OLD, and reset the LOGIN state as well
1836 1836 * (this will force the ULPs to perform a LOGIN after calling
1837 1837 * fc_portgetmap() during RESUME/PM_RESUME)
1838 1838 */
1839 1839 for (index = 0; index < pwwn_table_size; index++) {
1840 1840 head = &port->fp_pwwn_table[index];
1841 1841 pd = head->pwwn_head;
1842 1842 while (pd != NULL) {
1843 1843 mutex_enter(&pd->pd_mutex);
1844 1844 fp_remote_port_offline(pd);
1845 1845 fctl_delist_did_table(port, pd);
1846 1846 pd->pd_state = PORT_DEVICE_VALID;
1847 1847 pd->pd_login_count = 0;
1848 1848 mutex_exit(&pd->pd_mutex);
1849 1849 pd = pd->pd_wwn_hnext;
1850 1850 }
1851 1851 }
1852 1852 }
1853 1853
1854 1854
1855 1855 /*
1856 1856 * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1857 1857 * Performs intializations for fc_packet_t structs.
1858 1858 * Returns 0 for success or -1 for failure.
1859 1859 *
1860 1860 * This function allocates DMA handles for both command and responses.
1861 1861 * Most of the ELSs used have both command and responses so it is strongly
1862 1862 * desired to move them to cache constructor routine.
1863 1863 *
1864 1864 * Context: Can sleep iff called with KM_SLEEP flag.
1865 1865 */
1866 1866 static int
1867 1867 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1868 1868 {
1869 1869 int (*cb) (caddr_t);
1870 1870 fc_packet_t *pkt;
1871 1871 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1872 1872 fc_local_port_t *port = (fc_local_port_t *)cdarg;
1873 1873
1874 1874 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1875 1875
1876 1876 cmd->cmd_next = NULL;
1877 1877 cmd->cmd_flags = 0;
1878 1878 cmd->cmd_dflags = 0;
1879 1879 cmd->cmd_job = NULL;
1880 1880 cmd->cmd_port = port;
1881 1881 pkt = &cmd->cmd_pkt;
1882 1882
1883 1883 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
1884 1884 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1885 1885 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1886 1886 &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1887 1887 return (-1);
1888 1888 }
1889 1889
1890 1890 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1891 1891 port->fp_fca_tran->fca_dma_attr, cb, NULL,
1892 1892 &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1893 1893 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1894 1894 return (-1);
1895 1895 }
1896 1896 } else {
1897 1897 pkt->pkt_cmd_dma = 0;
1898 1898 pkt->pkt_resp_dma = 0;
1899 1899 }
1900 1900
1901 1901 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1902 1902 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1903 1903 pkt->pkt_data_cookie_cnt = 0;
1904 1904 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1905 1905 pkt->pkt_data_cookie = NULL;
1906 1906 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1907 1907
1908 1908 return (0);
1909 1909 }
1910 1910
1911 1911
1912 1912 /*
1913 1913 * fp_cache_destructor: Destructor function for kmem_cache_create().
1914 1914 * Performs un-intializations for fc_packet_t structs.
1915 1915 */
1916 1916 /* ARGSUSED */
1917 1917 static void
1918 1918 fp_cache_destructor(void *buf, void *cdarg)
1919 1919 {
1920 1920 fp_cmd_t *cmd = (fp_cmd_t *)buf;
1921 1921 fc_packet_t *pkt;
1922 1922
1923 1923 pkt = &cmd->cmd_pkt;
1924 1924 if (pkt->pkt_cmd_dma) {
1925 1925 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1926 1926 }
1927 1927
1928 1928 if (pkt->pkt_resp_dma) {
1929 1929 ddi_dma_free_handle(&pkt->pkt_resp_dma);
1930 1930 }
1931 1931 }
1932 1932
1933 1933
1934 1934 /*
1935 1935 * Packet allocation for ELS and any other port driver commands
1936 1936 *
1937 1937 * Some ELSs like FLOGI and PLOGI are critical for topology and
1938 1938 * device discovery and a system's inability to allocate memory
1939 1939 * or DVMA resources while performing some of these critical ELSs
1940 1940 * cause a lot of problem. While memory allocation failures are
1941 1941 * rare, DVMA resource failures are common as the applications
1942 1942 * are becoming more and more powerful on huge servers. So it
1943 1943 * is desirable to have a framework support to reserve a fragment
1944 1944 * of DVMA. So until this is fixed the correct way, the suffering
1945 1945 * is huge whenever a LIP happens at a time DVMA resources are
1946 1946 * drained out completely - So an attempt needs to be made to
1947 1947 * KM_SLEEP while requesting for these resources, hoping that
1948 1948 * the requests won't hang forever.
1949 1949 *
1950 1950 * The fc_remote_port_t argument is stored into the pkt_pd field in the
1951 1951 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This
1952 1952 * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1953 1953 * If there is no fc_remote_port_t associated with the fc_packet_t, then
1954 1954 * fp_alloc_pkt() must be called with pd set to NULL.
1955 1955 *
1956 1956 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
1957 1957 * actually, it's a design fault. But there's no problem for physical
1958 1958 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
1959 1959 *
1960 1960 * For FCAs that don't support DMA, such as fcoei, we will use
1961 1961 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
1962 1962 */
1963 1963
1964 1964 static fp_cmd_t *
1965 1965 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1966 1966 fc_remote_port_t *pd)
1967 1967 {
1968 1968 int rval;
1969 1969 ulong_t real_len;
1970 1970 fp_cmd_t *cmd;
1971 1971 fc_packet_t *pkt;
1972 1972 int (*cb) (caddr_t);
1973 1973 ddi_dma_cookie_t pkt_cookie;
1974 1974 ddi_dma_cookie_t *cp;
1975 1975 uint32_t cnt;
1976 1976
1977 1977 ASSERT(!MUTEX_HELD(&port->fp_mutex));
1978 1978
1979 1979 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1980 1980
1981 1981 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1982 1982 if (cmd == NULL) {
1983 1983 return (cmd);
1984 1984 }
1985 1985
1986 1986 cmd->cmd_ulp_pkt = NULL;
1987 1987 cmd->cmd_flags = 0;
1988 1988 pkt = &cmd->cmd_pkt;
1989 1989 ASSERT(cmd->cmd_dflags == 0);
1990 1990
1991 1991 pkt->pkt_datalen = 0;
1992 1992 pkt->pkt_data = NULL;
1993 1993 pkt->pkt_state = 0;
1994 1994 pkt->pkt_action = 0;
1995 1995 pkt->pkt_reason = 0;
1996 1996 pkt->pkt_expln = 0;
1997 1997 pkt->pkt_cmd = NULL;
1998 1998 pkt->pkt_resp = NULL;
1999 1999 pkt->pkt_fctl_rsvd1 = NULL;
2000 2000 pkt->pkt_fctl_rsvd2 = NULL;
2001 2001
2002 2002 /*
2003 2003 * Init pkt_pd with the given pointer; this must be done _before_
2004 2004 * the call to fc_ulp_init_packet().
2005 2005 */
2006 2006 pkt->pkt_pd = pd;
2007 2007
2008 2008 /* Now call the FCA driver to init its private, per-packet fields */
2009 2009 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
2010 2010 goto alloc_pkt_failed;
2011 2011 }
2012 2012
2013 2013 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2014 2014 ASSERT(pkt->pkt_cmd_dma != NULL);
2015 2015
2016 2016 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2017 2017 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
2018 2018 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2019 2019 &pkt->pkt_cmd_acc);
2020 2020
2021 2021 if (rval != DDI_SUCCESS) {
2022 2022 goto alloc_pkt_failed;
2023 2023 }
2024 2024 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
2025 2025
2026 2026 if (real_len < cmd_len) {
2027 2027 goto alloc_pkt_failed;
2028 2028 }
2029 2029
2030 2030 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2031 2031 pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2032 2032 DDI_DMA_CONSISTENT, cb, NULL,
2033 2033 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2034 2034
2035 2035 if (rval != DDI_DMA_MAPPED) {
2036 2036 goto alloc_pkt_failed;
2037 2037 }
2038 2038
2039 2039 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2040 2040
2041 2041 if (pkt->pkt_cmd_cookie_cnt >
2042 2042 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2043 2043 goto alloc_pkt_failed;
2044 2044 }
2045 2045
2046 2046 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2047 2047
2048 2048 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2049 2049 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2050 2050 KM_NOSLEEP);
2051 2051
2052 2052 if (cp == NULL) {
2053 2053 goto alloc_pkt_failed;
2054 2054 }
2055 2055
2056 2056 *cp = pkt_cookie;
2057 2057 cp++;
2058 2058 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2059 2059 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2060 2060 *cp = pkt_cookie;
2061 2061 }
2062 2062 } else if (cmd_len != 0) {
2063 2063 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
2064 2064 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
2065 2065 }
2066 2066
2067 2067 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2068 2068 ASSERT(pkt->pkt_resp_dma != NULL);
2069 2069
2070 2070 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2071 2071 port->fp_fca_tran->fca_acc_attr,
2072 2072 DDI_DMA_CONSISTENT, cb, NULL,
2073 2073 (caddr_t *)&pkt->pkt_resp, &real_len,
2074 2074 &pkt->pkt_resp_acc);
2075 2075
2076 2076 if (rval != DDI_SUCCESS) {
2077 2077 goto alloc_pkt_failed;
2078 2078 }
2079 2079 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2080 2080
2081 2081 if (real_len < resp_len) {
2082 2082 goto alloc_pkt_failed;
2083 2083 }
2084 2084
2085 2085 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2086 2086 pkt->pkt_resp, real_len, DDI_DMA_READ |
2087 2087 DDI_DMA_CONSISTENT, cb, NULL,
2088 2088 &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2089 2089
2090 2090 if (rval != DDI_DMA_MAPPED) {
2091 2091 goto alloc_pkt_failed;
2092 2092 }
2093 2093
2094 2094 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2095 2095
2096 2096 if (pkt->pkt_resp_cookie_cnt >
2097 2097 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2098 2098 goto alloc_pkt_failed;
2099 2099 }
2100 2100
2101 2101 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2102 2102
2103 2103 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2104 2104 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2105 2105 KM_NOSLEEP);
2106 2106
2107 2107 if (cp == NULL) {
2108 2108 goto alloc_pkt_failed;
2109 2109 }
2110 2110
2111 2111 *cp = pkt_cookie;
2112 2112 cp++;
2113 2113 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2114 2114 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2115 2115 *cp = pkt_cookie;
2116 2116 }
2117 2117 } else if (resp_len != 0) {
2118 2118 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
2119 2119 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
2120 2120 }
2121 2121
2122 2122 pkt->pkt_cmdlen = cmd_len;
2123 2123 pkt->pkt_rsplen = resp_len;
2124 2124 pkt->pkt_ulp_private = cmd;
2125 2125
2126 2126 return (cmd);
2127 2127
2128 2128 alloc_pkt_failed:
2129 2129
2130 2130 fp_free_dma(cmd);
2131 2131
2132 2132 if (pkt->pkt_cmd_cookie != NULL) {
2133 2133 kmem_free(pkt->pkt_cmd_cookie,
2134 2134 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2135 2135 pkt->pkt_cmd_cookie = NULL;
2136 2136 }
2137 2137
2138 2138 if (pkt->pkt_resp_cookie != NULL) {
2139 2139 kmem_free(pkt->pkt_resp_cookie,
2140 2140 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2141 2141 pkt->pkt_resp_cookie = NULL;
2142 2142 }
2143 2143
2144 2144 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2145 2145 if (pkt->pkt_cmd) {
2146 2146 kmem_free(pkt->pkt_cmd, cmd_len);
2147 2147 }
2148 2148
2149 2149 if (pkt->pkt_resp) {
2150 2150 kmem_free(pkt->pkt_resp, resp_len);
2151 2151 }
2152 2152 }
2153 2153
2154 2154 kmem_cache_free(port->fp_pkt_cache, cmd);
2155 2155
2156 2156 return (NULL);
2157 2157 }
2158 2158
2159 2159
2160 2160 /*
2161 2161 * Free FC packet
2162 2162 */
2163 2163 static void
2164 2164 fp_free_pkt(fp_cmd_t *cmd)
2165 2165 {
2166 2166 fc_local_port_t *port;
2167 2167 fc_packet_t *pkt;
2168 2168
2169 2169 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2170 2170
2171 2171 cmd->cmd_next = NULL;
2172 2172 cmd->cmd_job = NULL;
2173 2173 pkt = &cmd->cmd_pkt;
2174 2174 pkt->pkt_ulp_private = 0;
2175 2175 pkt->pkt_tran_flags = 0;
2176 2176 pkt->pkt_tran_type = 0;
2177 2177 port = cmd->cmd_port;
2178 2178
2179 2179 if (pkt->pkt_cmd_cookie != NULL) {
2180 2180 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2181 2181 sizeof (ddi_dma_cookie_t));
2182 2182 pkt->pkt_cmd_cookie = NULL;
2183 2183 }
2184 2184
2185 2185 if (pkt->pkt_resp_cookie != NULL) {
2186 2186 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2187 2187 sizeof (ddi_dma_cookie_t));
2188 2188 pkt->pkt_resp_cookie = NULL;
2189 2189 }
2190 2190
2191 2191 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2192 2192 if (pkt->pkt_cmd) {
2193 2193 kmem_free(pkt->pkt_cmd,
2194 2194 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
2195 2195 }
2196 2196
2197 2197 if (pkt->pkt_resp) {
2198 2198 kmem_free(pkt->pkt_resp,
2199 2199 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
2200 2200 }
2201 2201 }
2202 2202
2203 2203 fp_free_dma(cmd);
2204 2204 (void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2205 2205 kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2206 2206 }
2207 2207
2208 2208
2209 2209 /*
2210 2210 * Release DVMA resources
2211 2211 */
2212 2212 static void
2213 2213 fp_free_dma(fp_cmd_t *cmd)
2214 2214 {
2215 2215 fc_packet_t *pkt = &cmd->cmd_pkt;
2216 2216
2217 2217 pkt->pkt_cmdlen = 0;
2218 2218 pkt->pkt_rsplen = 0;
2219 2219 pkt->pkt_tran_type = 0;
2220 2220 pkt->pkt_tran_flags = 0;
2221 2221
2222 2222 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2223 2223 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2224 2224 }
2225 2225
2226 2226 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2227 2227 if (pkt->pkt_cmd_acc) {
2228 2228 ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2229 2229 }
2230 2230 }
2231 2231
2232 2232 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2233 2233 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2234 2234 }
2235 2235
2236 2236 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2237 2237 if (pkt->pkt_resp_acc) {
2238 2238 ddi_dma_mem_free(&pkt->pkt_resp_acc);
2239 2239 }
2240 2240 }
2241 2241 cmd->cmd_dflags = 0;
2242 2242 }
2243 2243
2244 2244
2245 2245 /*
2246 2246 * Dedicated thread to perform various activities. One thread for
2247 2247 * each fc_local_port_t (driver soft state) instance.
2248 2248 * Note, this effectively works out to one thread for each local
2249 2249 * port, but there are also some Solaris taskq threads in use on a per-local
2250 2250 * port basis; these also need to be taken into consideration.
2251 2251 */
2252 2252 static void
2253 2253 fp_job_handler(fc_local_port_t *port)
2254 2254 {
2255 2255 int rval;
2256 2256 uint32_t *d_id;
2257 2257 fc_remote_port_t *pd;
2258 2258 job_request_t *job;
2259 2259
2260 2260 #ifndef __lock_lint
2261 2261 /*
2262 2262 * Solaris-internal stuff for proper operation of kernel threads
2263 2263 * with Solaris CPR.
2264 2264 */
2265 2265 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
2266 2266 callb_generic_cpr, "fp_job_handler");
2267 2267 #endif
2268 2268
2269 2269
2270 2270 /* Loop forever waiting for work to do */
2271 2271 for (;;) {
2272 2272
2273 2273 mutex_enter(&port->fp_mutex);
2274 2274
2275 2275 /*
2276 2276 * Sleep if no work to do right now, or if we want
2277 2277 * to suspend or power-down.
2278 2278 */
2279 2279 while (port->fp_job_head == NULL ||
2280 2280 (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2281 2281 FP_SOFT_SUSPEND))) {
2282 2282 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2283 2283 cv_wait(&port->fp_cv, &port->fp_mutex);
2284 2284 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2285 2285 }
2286 2286
2287 2287 /*
2288 2288 * OK, we've just been woken up, so retrieve the next entry
2289 2289 * from the head of the job queue for this local port.
2290 2290 */
2291 2291 job = fctl_deque_job(port);
2292 2292
2293 2293 /*
2294 2294 * Handle all the fp driver's supported job codes here
2295 2295 * in this big honkin' switch.
2296 2296 */
2297 2297 switch (job->job_code) {
2298 2298 case JOB_PORT_SHUTDOWN:
2299 2299 /*
2300 2300 * fp_port_shutdown() is only called from here. This
2301 2301 * will prepare the local port instance (softstate)
2302 2302 * for detaching. This cancels timeout callbacks,
2303 2303 * executes LOGOs with remote ports, cleans up tables,
2304 2304 * and deallocates data structs.
2305 2305 */
2306 2306 fp_port_shutdown(port, job);
2307 2307
2308 2308 /*
2309 2309 * This will exit the job thread.
2310 2310 */
2311 2311 #ifndef __lock_lint
2312 2312 CALLB_CPR_EXIT(&(port->fp_cpr_info));
2313 2313 #else
2314 2314 mutex_exit(&port->fp_mutex);
2315 2315 #endif
2316 2316 fctl_jobdone(job);
2317 2317 thread_exit();
2318 2318
2319 2319 /* NOTREACHED */
2320 2320
2321 2321 case JOB_ATTACH_ULP: {
2322 2322 /*
2323 2323 * This job is spawned in response to a ULP calling
2324 2324 * fc_ulp_add().
2325 2325 */
2326 2326
2327 2327 boolean_t do_attach_ulps = B_TRUE;
2328 2328
2329 2329 /*
2330 2330 * If fp is detaching, we don't want to call
2331 2331 * fp_startup_done as this asynchronous
2332 2332 * notification may interfere with the re-attach.
2333 2333 */
2334 2334
2335 2335 if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2336 2336 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2337 2337 do_attach_ulps = B_FALSE;
2338 2338 } else {
2339 2339 /*
2340 2340 * We are going to force the transport
2341 2341 * to attach to the ULPs, so set
2342 2342 * fp_ulp_attach. This will keep any
2343 2343 * potential detach from occurring until
2344 2344 * we are done.
2345 2345 */
2346 2346 port->fp_ulp_attach = 1;
2347 2347 }
2348 2348
2349 2349 mutex_exit(&port->fp_mutex);
2350 2350
2351 2351 /*
2352 2352 * NOTE: Since we just dropped the mutex, there is now
2353 2353 * a race window where the fp_soft_state check above
2354 2354 * could change here. This race is covered because an
2355 2355 * additional check was added in the functions hidden
2356 2356 * under fp_startup_done().
2357 2357 */
2358 2358 if (do_attach_ulps == B_TRUE) {
2359 2359 /*
2360 2360 * This goes thru a bit of a convoluted call
2361 2361 * chain before spawning off a DDI taskq
2362 2362 * request to perform the actual attach
2363 2363 * operations. Blocking can occur at a number
2364 2364 * of points.
2365 2365 */
2366 2366 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2367 2367 }
2368 2368 job->job_result = FC_SUCCESS;
2369 2369 fctl_jobdone(job);
2370 2370 break;
2371 2371 }
2372 2372
2373 2373 case JOB_ULP_NOTIFY: {
2374 2374 /*
2375 2375 * Pass state change notifications up to any/all
2376 2376 * registered ULPs.
2377 2377 */
2378 2378 uint32_t statec;
2379 2379
2380 2380 statec = job->job_ulp_listlen;
2381 2381 if (statec == FC_STATE_RESET_REQUESTED) {
2382 2382 port->fp_last_task = port->fp_task;
2383 2383 port->fp_task = FP_TASK_OFFLINE;
2384 2384 fp_port_offline(port, 0);
2385 2385 port->fp_task = port->fp_last_task;
2386 2386 port->fp_last_task = FP_TASK_IDLE;
2387 2387 }
2388 2388
2389 2389 if (--port->fp_statec_busy == 0) {
2390 2390 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2391 2391 }
2392 2392
2393 2393 mutex_exit(&port->fp_mutex);
2394 2394
2395 2395 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2396 2396 fctl_jobdone(job);
2397 2397 break;
2398 2398 }
2399 2399
2400 2400 case JOB_PLOGI_ONE:
2401 2401 /*
2402 2402 * Issue a PLOGI to a single remote port. Multiple
2403 2403 * PLOGIs to different remote ports may occur in
2404 2404 * parallel.
2405 2405 * This can create the fc_remote_port_t if it does not
2406 2406 * already exist.
2407 2407 */
2408 2408
2409 2409 mutex_exit(&port->fp_mutex);
2410 2410 d_id = (uint32_t *)job->job_private;
2411 2411 pd = fctl_get_remote_port_by_did(port, *d_id);
2412 2412
2413 2413 if (pd) {
2414 2414 mutex_enter(&pd->pd_mutex);
2415 2415 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2416 2416 pd->pd_login_count++;
2417 2417 mutex_exit(&pd->pd_mutex);
2418 2418 job->job_result = FC_SUCCESS;
2419 2419 fctl_jobdone(job);
2420 2420 break;
2421 2421 }
2422 2422 mutex_exit(&pd->pd_mutex);
2423 2423 } else {
2424 2424 mutex_enter(&port->fp_mutex);
2425 2425 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2426 2426 mutex_exit(&port->fp_mutex);
2427 2427 pd = fp_create_remote_port_by_ns(port,
2428 2428 *d_id, KM_SLEEP);
2429 2429 if (pd == NULL) {
2430 2430 job->job_result = FC_FAILURE;
2431 2431 fctl_jobdone(job);
2432 2432 break;
2433 2433 }
2434 2434 } else {
2435 2435 mutex_exit(&port->fp_mutex);
2436 2436 }
2437 2437 }
2438 2438
2439 2439 job->job_flags |= JOB_TYPE_FP_ASYNC;
2440 2440 job->job_counter = 1;
2441 2441
2442 2442 rval = fp_port_login(port, *d_id, job,
2443 2443 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2444 2444
2445 2445 if (rval != FC_SUCCESS) {
2446 2446 job->job_result = rval;
2447 2447 fctl_jobdone(job);
2448 2448 }
2449 2449 break;
2450 2450
2451 2451 case JOB_LOGO_ONE: {
2452 2452 /*
2453 2453 * Issue a PLOGO to a single remote port. Multiple
2454 2454 * PLOGOs to different remote ports may occur in
2455 2455 * parallel.
2456 2456 */
2457 2457 fc_remote_port_t *pd;
2458 2458
2459 2459 #ifndef __lock_lint
2460 2460 ASSERT(job->job_counter > 0);
2461 2461 #endif
2462 2462
2463 2463 pd = (fc_remote_port_t *)job->job_ulp_pkts;
2464 2464
2465 2465 mutex_enter(&pd->pd_mutex);
2466 2466 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2467 2467 mutex_exit(&pd->pd_mutex);
2468 2468 job->job_result = FC_LOGINREQ;
2469 2469 mutex_exit(&port->fp_mutex);
2470 2470 fctl_jobdone(job);
2471 2471 break;
2472 2472 }
2473 2473 if (pd->pd_login_count > 1) {
2474 2474 pd->pd_login_count--;
2475 2475 mutex_exit(&pd->pd_mutex);
2476 2476 job->job_result = FC_SUCCESS;
2477 2477 mutex_exit(&port->fp_mutex);
2478 2478 fctl_jobdone(job);
2479 2479 break;
2480 2480 }
2481 2481 mutex_exit(&pd->pd_mutex);
2482 2482 mutex_exit(&port->fp_mutex);
2483 2483 job->job_flags |= JOB_TYPE_FP_ASYNC;
2484 2484 (void) fp_logout(port, pd, job);
2485 2485 break;
2486 2486 }
2487 2487
2488 2488 case JOB_FCIO_LOGIN:
2489 2489 /*
2490 2490 * PLOGI initiated at ioctl request.
2491 2491 */
2492 2492 mutex_exit(&port->fp_mutex);
2493 2493 job->job_result =
2494 2494 fp_fcio_login(port, job->job_private, job);
2495 2495 fctl_jobdone(job);
2496 2496 break;
2497 2497
2498 2498 case JOB_FCIO_LOGOUT:
2499 2499 /*
2500 2500 * PLOGO initiated at ioctl request.
2501 2501 */
2502 2502 mutex_exit(&port->fp_mutex);
2503 2503 job->job_result =
2504 2504 fp_fcio_logout(port, job->job_private, job);
2505 2505 fctl_jobdone(job);
2506 2506 break;
2507 2507
2508 2508 case JOB_PORT_GETMAP:
2509 2509 case JOB_PORT_GETMAP_PLOGI_ALL: {
2510 2510 port->fp_last_task = port->fp_task;
2511 2511 port->fp_task = FP_TASK_GETMAP;
2512 2512
2513 2513 switch (port->fp_topology) {
2514 2514 case FC_TOP_PRIVATE_LOOP:
2515 2515 job->job_counter = 1;
2516 2516
2517 2517 fp_get_loopmap(port, job);
2518 2518 mutex_exit(&port->fp_mutex);
2519 2519 fp_jobwait(job);
2520 2520 fctl_fillout_map(port,
2521 2521 (fc_portmap_t **)job->job_private,
2522 2522 (uint32_t *)job->job_arg, 1, 0, 0);
2523 2523 fctl_jobdone(job);
2524 2524 mutex_enter(&port->fp_mutex);
2525 2525 break;
2526 2526
2527 2527 case FC_TOP_PUBLIC_LOOP:
2528 2528 case FC_TOP_FABRIC:
2529 2529 mutex_exit(&port->fp_mutex);
2530 2530 job->job_counter = 1;
2531 2531
2532 2532 job->job_result = fp_ns_getmap(port,
2533 2533 job, (fc_portmap_t **)job->job_private,
2534 2534 (uint32_t *)job->job_arg,
2535 2535 FCTL_GAN_START_ID);
2536 2536 fctl_jobdone(job);
2537 2537 mutex_enter(&port->fp_mutex);
2538 2538 break;
2539 2539
2540 2540 case FC_TOP_PT_PT:
2541 2541 mutex_exit(&port->fp_mutex);
2542 2542 fctl_fillout_map(port,
2543 2543 (fc_portmap_t **)job->job_private,
2544 2544 (uint32_t *)job->job_arg, 1, 0, 0);
2545 2545 fctl_jobdone(job);
2546 2546 mutex_enter(&port->fp_mutex);
2547 2547 break;
2548 2548
2549 2549 default:
2550 2550 mutex_exit(&port->fp_mutex);
2551 2551 fctl_jobdone(job);
2552 2552 mutex_enter(&port->fp_mutex);
2553 2553 break;
2554 2554 }
2555 2555 port->fp_task = port->fp_last_task;
2556 2556 port->fp_last_task = FP_TASK_IDLE;
2557 2557 mutex_exit(&port->fp_mutex);
2558 2558 break;
2559 2559 }
2560 2560
2561 2561 case JOB_PORT_OFFLINE: {
2562 2562 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2563 2563
2564 2564 port->fp_last_task = port->fp_task;
2565 2565 port->fp_task = FP_TASK_OFFLINE;
2566 2566
2567 2567 if (port->fp_statec_busy > 2) {
2568 2568 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2569 2569 fp_port_offline(port, 0);
2570 2570 if (--port->fp_statec_busy == 0) {
2571 2571 port->fp_soft_state &=
2572 2572 ~FP_SOFT_IN_STATEC_CB;
2573 2573 }
2574 2574 } else {
2575 2575 fp_port_offline(port, 1);
2576 2576 }
2577 2577
2578 2578 port->fp_task = port->fp_last_task;
2579 2579 port->fp_last_task = FP_TASK_IDLE;
2580 2580
2581 2581 mutex_exit(&port->fp_mutex);
2582 2582
2583 2583 fctl_jobdone(job);
2584 2584 break;
2585 2585 }
2586 2586
2587 2587 case JOB_PORT_STARTUP: {
2588 2588 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2589 2589 if (port->fp_statec_busy > 1) {
2590 2590 mutex_exit(&port->fp_mutex);
2591 2591 break;
2592 2592 }
2593 2593 mutex_exit(&port->fp_mutex);
2594 2594
2595 2595 FP_TRACE(FP_NHEAD2(9, rval),
2596 2596 "Topology discovery failed");
2597 2597 break;
2598 2598 }
2599 2599
2600 2600 /*
2601 2601 * Attempt building device handles in case
2602 2602 * of private Loop.
2603 2603 */
2604 2604 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2605 2605 job->job_counter = 1;
2606 2606
2607 2607 fp_get_loopmap(port, job);
2608 2608 mutex_exit(&port->fp_mutex);
2609 2609 fp_jobwait(job);
2610 2610 mutex_enter(&port->fp_mutex);
2611 2611 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2612 2612 ASSERT(port->fp_total_devices == 0);
2613 2613 port->fp_total_devices =
2614 2614 port->fp_dev_count;
2615 2615 }
2616 2616 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2617 2617 /*
2618 2618 * Hack to avoid state changes going up early
2619 2619 */
2620 2620 port->fp_statec_busy++;
2621 2621 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2622 2622
2623 2623 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2624 2624 fp_fabric_online(port, job);
2625 2625 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2626 2626 }
2627 2627 mutex_exit(&port->fp_mutex);
2628 2628 fctl_jobdone(job);
2629 2629 break;
2630 2630 }
2631 2631
2632 2632 case JOB_PORT_ONLINE: {
2633 2633 char *newtop;
2634 2634 char *oldtop;
2635 2635 uint32_t old_top;
2636 2636
2637 2637 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2638 2638
2639 2639 /*
2640 2640 * Bail out early if there are a lot of
2641 2641 * state changes in the pipeline
2642 2642 */
2643 2643 if (port->fp_statec_busy > 1) {
2644 2644 --port->fp_statec_busy;
2645 2645 mutex_exit(&port->fp_mutex);
2646 2646 fctl_jobdone(job);
2647 2647 break;
2648 2648 }
2649 2649
2650 2650 switch (old_top = port->fp_topology) {
2651 2651 case FC_TOP_PRIVATE_LOOP:
2652 2652 oldtop = "Private Loop";
2653 2653 break;
2654 2654
2655 2655 case FC_TOP_PUBLIC_LOOP:
2656 2656 oldtop = "Public Loop";
2657 2657 break;
2658 2658
2659 2659 case FC_TOP_PT_PT:
2660 2660 oldtop = "Point to Point";
2661 2661 break;
2662 2662
2663 2663 case FC_TOP_FABRIC:
2664 2664 oldtop = "Fabric";
2665 2665 break;
2666 2666
2667 2667 default:
2668 2668 oldtop = NULL;
2669 2669 break;
2670 2670 }
2671 2671
2672 2672 port->fp_last_task = port->fp_task;
2673 2673 port->fp_task = FP_TASK_ONLINE;
2674 2674
2675 2675 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2676 2676
2677 2677 port->fp_task = port->fp_last_task;
2678 2678 port->fp_last_task = FP_TASK_IDLE;
2679 2679
2680 2680 if (port->fp_statec_busy > 1) {
2681 2681 --port->fp_statec_busy;
2682 2682 mutex_exit(&port->fp_mutex);
2683 2683 break;
2684 2684 }
2685 2685
2686 2686 port->fp_state = FC_STATE_OFFLINE;
2687 2687
2688 2688 FP_TRACE(FP_NHEAD2(9, rval),
2689 2689 "Topology discovery failed");
2690 2690
2691 2691 if (--port->fp_statec_busy == 0) {
2692 2692 port->fp_soft_state &=
2693 2693 ~FP_SOFT_IN_STATEC_CB;
2694 2694 }
2695 2695
2696 2696 if (port->fp_offline_tid == NULL) {
2697 2697 port->fp_offline_tid =
2698 2698 timeout(fp_offline_timeout,
2699 2699 (caddr_t)port, fp_offline_ticks);
2700 2700 }
2701 2701
2702 2702 mutex_exit(&port->fp_mutex);
2703 2703 break;
2704 2704 }
2705 2705
2706 2706 switch (port->fp_topology) {
2707 2707 case FC_TOP_PRIVATE_LOOP:
2708 2708 newtop = "Private Loop";
2709 2709 break;
2710 2710
2711 2711 case FC_TOP_PUBLIC_LOOP:
2712 2712 newtop = "Public Loop";
2713 2713 break;
2714 2714
2715 2715 case FC_TOP_PT_PT:
2716 2716 newtop = "Point to Point";
2717 2717 break;
2718 2718
2719 2719 case FC_TOP_FABRIC:
2720 2720 newtop = "Fabric";
2721 2721 break;
2722 2722
2723 2723 default:
2724 2724 newtop = NULL;
2725 2725 break;
2726 2726 }
2727 2727
2728 2728 if (oldtop && newtop && strcmp(oldtop, newtop)) {
2729 2729 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2730 2730 "Change in FC Topology old = %s new = %s",
2731 2731 oldtop, newtop);
2732 2732 }
2733 2733
2734 2734 switch (port->fp_topology) {
2735 2735 case FC_TOP_PRIVATE_LOOP: {
2736 2736 int orphan = (old_top == FC_TOP_FABRIC ||
2737 2737 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2738 2738
2739 2739 mutex_exit(&port->fp_mutex);
2740 2740 fp_loop_online(port, job, orphan);
2741 2741 break;
2742 2742 }
2743 2743
2744 2744 case FC_TOP_PUBLIC_LOOP:
2745 2745 /* FALLTHROUGH */
2746 2746 case FC_TOP_FABRIC:
2747 2747 fp_fabric_online(port, job);
2748 2748 mutex_exit(&port->fp_mutex);
2749 2749 break;
2750 2750
2751 2751 case FC_TOP_PT_PT:
2752 2752 fp_p2p_online(port, job);
2753 2753 mutex_exit(&port->fp_mutex);
2754 2754 break;
2755 2755
2756 2756 default:
2757 2757 if (--port->fp_statec_busy != 0) {
2758 2758 /*
2759 2759 * Watch curiously at what the next
2760 2760 * state transition can do.
2761 2761 */
2762 2762 mutex_exit(&port->fp_mutex);
2763 2763 break;
2764 2764 }
2765 2765
2766 2766 FP_TRACE(FP_NHEAD2(9, 0),
2767 2767 "Topology Unknown, Offlining the port..");
2768 2768
2769 2769 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2770 2770 port->fp_state = FC_STATE_OFFLINE;
2771 2771
2772 2772 if (port->fp_offline_tid == NULL) {
2773 2773 port->fp_offline_tid =
2774 2774 timeout(fp_offline_timeout,
2775 2775 (caddr_t)port, fp_offline_ticks);
2776 2776 }
2777 2777 mutex_exit(&port->fp_mutex);
2778 2778 break;
2779 2779 }
2780 2780
2781 2781 mutex_enter(&port->fp_mutex);
2782 2782
2783 2783 port->fp_task = port->fp_last_task;
2784 2784 port->fp_last_task = FP_TASK_IDLE;
2785 2785
2786 2786 mutex_exit(&port->fp_mutex);
2787 2787
2788 2788 fctl_jobdone(job);
2789 2789 break;
2790 2790 }
2791 2791
2792 2792 case JOB_PLOGI_GROUP: {
2793 2793 mutex_exit(&port->fp_mutex);
2794 2794 fp_plogi_group(port, job);
2795 2795 break;
2796 2796 }
2797 2797
2798 2798 case JOB_UNSOL_REQUEST: {
2799 2799 mutex_exit(&port->fp_mutex);
2800 2800 fp_handle_unsol_buf(port,
2801 2801 (fc_unsol_buf_t *)job->job_private, job);
2802 2802 fctl_dealloc_job(job);
2803 2803 break;
2804 2804 }
2805 2805
2806 2806 case JOB_NS_CMD: {
2807 2807 fctl_ns_req_t *ns_cmd;
2808 2808
2809 2809 mutex_exit(&port->fp_mutex);
2810 2810
2811 2811 job->job_flags |= JOB_TYPE_FP_ASYNC;
2812 2812 ns_cmd = (fctl_ns_req_t *)job->job_private;
2813 2813 if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2814 2814 ns_cmd->ns_cmd_code > NS_DA_ID) {
2815 2815 job->job_result = FC_BADCMD;
2816 2816 fctl_jobdone(job);
2817 2817 break;
2818 2818 }
2819 2819
2820 2820 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2821 2821 if (ns_cmd->ns_pd != NULL) {
2822 2822 job->job_result = FC_BADOBJECT;
2823 2823 fctl_jobdone(job);
2824 2824 break;
2825 2825 }
2826 2826
2827 2827 job->job_counter = 1;
2828 2828
2829 2829 rval = fp_ns_reg(port, ns_cmd->ns_pd,
2830 2830 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2831 2831
2832 2832 if (rval != FC_SUCCESS) {
2833 2833 job->job_result = rval;
2834 2834 fctl_jobdone(job);
2835 2835 }
2836 2836 break;
2837 2837 }
2838 2838 job->job_result = FC_SUCCESS;
2839 2839 job->job_counter = 1;
2840 2840
2841 2841 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2842 2842 if (rval != FC_SUCCESS) {
2843 2843 fctl_jobdone(job);
2844 2844 }
2845 2845 break;
2846 2846 }
2847 2847
2848 2848 case JOB_LINK_RESET: {
2849 2849 la_wwn_t *pwwn;
2850 2850 uint32_t topology;
2851 2851
2852 2852 pwwn = (la_wwn_t *)job->job_private;
2853 2853 ASSERT(pwwn != NULL);
2854 2854
2855 2855 topology = port->fp_topology;
2856 2856 mutex_exit(&port->fp_mutex);
2857 2857
2858 2858 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2859 2859 topology == FC_TOP_PRIVATE_LOOP) {
2860 2860 job->job_flags |= JOB_TYPE_FP_ASYNC;
2861 2861 rval = port->fp_fca_tran->fca_reset(
2862 2862 port->fp_fca_handle, FC_FCA_LINK_RESET);
2863 2863 job->job_result = rval;
2864 2864 fp_jobdone(job);
2865 2865 } else {
2866 2866 ASSERT((job->job_flags &
2867 2867 JOB_TYPE_FP_ASYNC) == 0);
2868 2868
2869 2869 if (FC_IS_TOP_SWITCH(topology)) {
2870 2870 rval = fp_remote_lip(port, pwwn,
2871 2871 KM_SLEEP, job);
2872 2872 } else {
2873 2873 rval = FC_FAILURE;
2874 2874 }
2875 2875 if (rval != FC_SUCCESS) {
2876 2876 job->job_result = rval;
2877 2877 }
2878 2878 fctl_jobdone(job);
2879 2879 }
2880 2880 break;
2881 2881 }
2882 2882
2883 2883 default:
2884 2884 mutex_exit(&port->fp_mutex);
2885 2885 job->job_result = FC_BADCMD;
2886 2886 fctl_jobdone(job);
2887 2887 break;
2888 2888 }
2889 2889 }
2890 2890 /* NOTREACHED */
2891 2891 }
2892 2892
2893 2893
2894 2894 /*
2895 2895 * Perform FC port bring up initialization
2896 2896 */
2897 2897 static int
2898 2898 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2899 2899 {
2900 2900 int rval;
2901 2901 uint32_t state;
2902 2902 uint32_t src_id;
2903 2903 fc_lilpmap_t *lilp_map;
2904 2904
2905 2905 ASSERT(MUTEX_HELD(&port->fp_mutex));
2906 2906 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2907 2907
2908 2908 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2909 2909 " port=%p, job=%p", port, job);
2910 2910
2911 2911 port->fp_topology = FC_TOP_UNKNOWN;
2912 2912 port->fp_port_id.port_id = 0;
2913 2913 state = FC_PORT_STATE_MASK(port->fp_state);
2914 2914
2915 2915 if (state == FC_STATE_OFFLINE) {
2916 2916 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2917 2917 job->job_result = FC_OFFLINE;
2918 2918 mutex_exit(&port->fp_mutex);
2919 2919 fctl_jobdone(job);
2920 2920 mutex_enter(&port->fp_mutex);
2921 2921 return (FC_OFFLINE);
2922 2922 }
2923 2923
2924 2924 if (state == FC_STATE_LOOP) {
2925 2925 port->fp_port_type.port_type = FC_NS_PORT_NL;
2926 2926 mutex_exit(&port->fp_mutex);
2927 2927
2928 2928 lilp_map = &port->fp_lilp_map;
2929 2929 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2930 2930 job->job_result = FC_FAILURE;
2931 2931 fctl_jobdone(job);
2932 2932
2933 2933 FP_TRACE(FP_NHEAD1(9, rval),
2934 2934 "LILP map Invalid or not present");
2935 2935 mutex_enter(&port->fp_mutex);
2936 2936 return (FC_FAILURE);
2937 2937 }
2938 2938
2939 2939 if (lilp_map->lilp_length == 0) {
2940 2940 job->job_result = FC_NO_MAP;
2941 2941 fctl_jobdone(job);
2942 2942 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2943 2943 "LILP map length zero");
2944 2944 mutex_enter(&port->fp_mutex);
2945 2945 return (FC_NO_MAP);
2946 2946 }
2947 2947 src_id = lilp_map->lilp_myalpa & 0xFF;
2948 2948 } else {
2949 2949 fc_remote_port_t *pd;
2950 2950 fc_fca_pm_t pm;
2951 2951 fc_fca_p2p_info_t p2p_info;
2952 2952 int pd_recepient;
2953 2953
2954 2954 /*
2955 2955 * Get P2P remote port info if possible
2956 2956 */
2957 2957 bzero((caddr_t)&pm, sizeof (pm));
2958 2958
2959 2959 pm.pm_cmd_flags = FC_FCA_PM_READ;
2960 2960 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2961 2961 pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2962 2962 pm.pm_data_buf = (caddr_t)&p2p_info;
2963 2963
2964 2964 rval = port->fp_fca_tran->fca_port_manage(
2965 2965 port->fp_fca_handle, &pm);
2966 2966
2967 2967 if (rval == FC_SUCCESS) {
2968 2968 port->fp_port_id.port_id = p2p_info.fca_d_id;
2969 2969 port->fp_port_type.port_type = FC_NS_PORT_N;
2970 2970 port->fp_topology = FC_TOP_PT_PT;
2971 2971 port->fp_total_devices = 1;
2972 2972 pd_recepient = fctl_wwn_cmp(
2973 2973 &port->fp_service_params.nport_ww_name,
2974 2974 &p2p_info.pwwn) < 0 ?
2975 2975 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2976 2976 mutex_exit(&port->fp_mutex);
2977 2977 pd = fctl_create_remote_port(port,
2978 2978 &p2p_info.nwwn,
2979 2979 &p2p_info.pwwn,
2980 2980 p2p_info.d_id,
2981 2981 pd_recepient, KM_NOSLEEP);
2982 2982 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2983 2983 " P2P port=%p pd=%p fp %x pd %x", port, pd,
2984 2984 port->fp_port_id.port_id, p2p_info.d_id);
2985 2985 mutex_enter(&port->fp_mutex);
2986 2986 return (FC_SUCCESS);
2987 2987 }
2988 2988 port->fp_port_type.port_type = FC_NS_PORT_N;
2989 2989 mutex_exit(&port->fp_mutex);
2990 2990 src_id = 0;
2991 2991 }
2992 2992
2993 2993 job->job_counter = 1;
2994 2994 job->job_result = FC_SUCCESS;
2995 2995
2996 2996 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2997 2997 KM_SLEEP)) != FC_SUCCESS) {
2998 2998 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2999 2999 job->job_result = FC_FAILURE;
3000 3000 fctl_jobdone(job);
3001 3001
3002 3002 mutex_enter(&port->fp_mutex);
3003 3003 if (port->fp_statec_busy <= 1) {
3004 3004 mutex_exit(&port->fp_mutex);
3005 3005 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
3006 3006 "Couldn't transport FLOGI");
3007 3007 mutex_enter(&port->fp_mutex);
3008 3008 }
3009 3009 return (FC_FAILURE);
3010 3010 }
3011 3011
3012 3012 fp_jobwait(job);
3013 3013
3014 3014 mutex_enter(&port->fp_mutex);
3015 3015 if (job->job_result == FC_SUCCESS) {
3016 3016 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3017 3017 mutex_exit(&port->fp_mutex);
3018 3018 fp_ns_init(port, job, KM_SLEEP);
3019 3019 mutex_enter(&port->fp_mutex);
3020 3020 }
3021 3021 } else {
3022 3022 if (state == FC_STATE_LOOP) {
3023 3023 port->fp_topology = FC_TOP_PRIVATE_LOOP;
3024 3024 port->fp_port_id.port_id =
3025 3025 port->fp_lilp_map.lilp_myalpa & 0xFF;
3026 3026 }
3027 3027 }
3028 3028
3029 3029 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
3030 3030 port, job);
3031 3031
3032 3032 return (FC_SUCCESS);
3033 3033 }
3034 3034
3035 3035
3036 3036 /*
3037 3037 * Perform ULP invocations following FC port startup
3038 3038 */
3039 3039 /* ARGSUSED */
3040 3040 static void
3041 3041 fp_startup_done(opaque_t arg, uchar_t result)
3042 3042 {
3043 3043 fc_local_port_t *port = arg;
3044 3044
3045 3045 fp_attach_ulps(port, FC_CMD_ATTACH);
3046 3046
3047 3047 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
3048 3048 }
3049 3049
3050 3050
3051 3051 /*
3052 3052 * Perform ULP port attach
3053 3053 */
3054 3054 static void
3055 3055 fp_ulp_port_attach(void *arg)
3056 3056 {
3057 3057 fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
3058 3058 fc_local_port_t *port = att->att_port;
3059 3059
3060 3060 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3061 3061 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3062 3062
3063 3063 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3064 3064
3065 3065 if (att->att_need_pm_idle == B_TRUE) {
3066 3066 fctl_idle_port(port);
3067 3067 }
3068 3068
3069 3069 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3070 3070 " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3071 3071
3072 3072 mutex_enter(&att->att_port->fp_mutex);
3073 3073 att->att_port->fp_ulp_attach = 0;
3074 3074
3075 3075 port->fp_task = port->fp_last_task;
3076 3076 port->fp_last_task = FP_TASK_IDLE;
3077 3077
3078 3078 cv_signal(&att->att_port->fp_attach_cv);
3079 3079
3080 3080 mutex_exit(&att->att_port->fp_mutex);
3081 3081
3082 3082 kmem_free(att, sizeof (fp_soft_attach_t));
3083 3083 }
3084 3084
3085 3085 /*
3086 3086 * Entry point to funnel all requests down to FCAs
3087 3087 */
3088 3088 static int
3089 3089 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3090 3090 {
3091 3091 int rval;
3092 3092
3093 3093 mutex_enter(&port->fp_mutex);
3094 3094 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3095 3095 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3096 3096 FC_STATE_OFFLINE))) {
3097 3097 /*
3098 3098 * This means there is more than one state change
3099 3099 * at this point of time - Since they are processed
3100 3100 * serially, any processing of the current one should
3101 3101 * be failed, failed and move up in processing the next
3102 3102 */
3103 3103 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3104 3104 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3105 3105 if (cmd->cmd_job) {
3106 3106 /*
3107 3107 * A state change that is going to be invalidated
3108 3108 * by another one already in the port driver's queue
3109 3109 * need not go up to all ULPs. This will minimize
3110 3110 * needless processing and ripples in ULP modules
3111 3111 */
3112 3112 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3113 3113 }
3114 3114 mutex_exit(&port->fp_mutex);
3115 3115 return (FC_STATEC_BUSY);
3116 3116 }
3117 3117
3118 3118 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3119 3119 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3120 3120 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3121 3121 mutex_exit(&port->fp_mutex);
3122 3122
3123 3123 return (FC_OFFLINE);
3124 3124 }
3125 3125 mutex_exit(&port->fp_mutex);
3126 3126
3127 3127 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3128 3128 if (rval != FC_SUCCESS) {
3129 3129 if (rval == FC_TRAN_BUSY) {
3130 3130 cmd->cmd_retry_interval = fp_retry_delay;
3131 3131 rval = fp_retry_cmd(&cmd->cmd_pkt);
3132 3132 if (rval == FC_FAILURE) {
3133 3133 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3134 3134 }
3135 3135 }
3136 3136 } else {
3137 3137 mutex_enter(&port->fp_mutex);
3138 3138 port->fp_out_fpcmds++;
3139 3139 mutex_exit(&port->fp_mutex);
3140 3140 }
3141 3141
3142 3142 return (rval);
3143 3143 }
3144 3144
3145 3145
3146 3146 /*
3147 3147 * Each time a timeout kicks in, walk the wait queue, decrement the
3148 3148 * the retry_interval, when the retry_interval becomes less than
3149 3149 * or equal to zero, re-transport the command: If the re-transport
3150 3150 * fails with BUSY, enqueue the command in the wait queue.
3151 3151 *
3152 3152 * In order to prevent looping forever because of commands enqueued
3153 3153 * from within this function itself, save the current tail pointer
3154 3154 * (in cur_tail) and exit the loop after serving this command.
3155 3155 */
3156 3156 static void
3157 3157 fp_resendcmd(void *port_handle)
3158 3158 {
3159 3159 int rval;
3160 3160 fc_local_port_t *port;
3161 3161 fp_cmd_t *cmd;
3162 3162 fp_cmd_t *cur_tail;
3163 3163
3164 3164 port = port_handle;
3165 3165 mutex_enter(&port->fp_mutex);
3166 3166 cur_tail = port->fp_wait_tail;
3167 3167 mutex_exit(&port->fp_mutex);
3168 3168
3169 3169 while ((cmd = fp_deque_cmd(port)) != NULL) {
3170 3170 cmd->cmd_retry_interval -= fp_retry_ticker;
3171 3171 /* Check if we are detaching */
3172 3172 if (port->fp_soft_state &
3173 3173 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3174 3174 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3175 3175 cmd->cmd_pkt.pkt_reason = 0;
3176 3176 fp_iodone(cmd);
3177 3177 } else if (cmd->cmd_retry_interval <= 0) {
3178 3178 rval = cmd->cmd_transport(port->fp_fca_handle,
3179 3179 &cmd->cmd_pkt);
3180 3180
3181 3181 if (rval != FC_SUCCESS) {
3182 3182 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3183 3183 if (--cmd->cmd_retry_count) {
3184 3184 fp_enque_cmd(port, cmd);
3185 3185 if (cmd == cur_tail) {
3186 3186 break;
3187 3187 }
3188 3188 continue;
3189 3189 }
3190 3190 cmd->cmd_pkt.pkt_state =
3191 3191 FC_PKT_TRAN_BSY;
3192 3192 } else {
3193 3193 cmd->cmd_pkt.pkt_state =
3194 3194 FC_PKT_TRAN_ERROR;
3195 3195 }
3196 3196 cmd->cmd_pkt.pkt_reason = 0;
3197 3197 fp_iodone(cmd);
3198 3198 } else {
3199 3199 mutex_enter(&port->fp_mutex);
3200 3200 port->fp_out_fpcmds++;
3201 3201 mutex_exit(&port->fp_mutex);
3202 3202 }
3203 3203 } else {
3204 3204 fp_enque_cmd(port, cmd);
3205 3205 }
3206 3206
3207 3207 if (cmd == cur_tail) {
3208 3208 break;
3209 3209 }
3210 3210 }
3211 3211
3212 3212 mutex_enter(&port->fp_mutex);
3213 3213 if (port->fp_wait_head) {
3214 3214 timeout_id_t tid;
3215 3215
3216 3216 mutex_exit(&port->fp_mutex);
3217 3217 tid = timeout(fp_resendcmd, (caddr_t)port,
3218 3218 fp_retry_ticks);
3219 3219 mutex_enter(&port->fp_mutex);
3220 3220 port->fp_wait_tid = tid;
3221 3221 } else {
3222 3222 port->fp_wait_tid = NULL;
3223 3223 }
3224 3224 mutex_exit(&port->fp_mutex);
3225 3225 }
3226 3226
3227 3227
3228 3228 /*
3229 3229 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3230 3230 *
3231 3231 * Yes, as you can see below, cmd_retry_count is used here too. That means
3232 3232 * the retries for BUSY are less if there were transport failures (transport
3233 3233 * failure means fca_transport failure). The goal is not to exceed overall
3234 3234 * retries set in the cmd_retry_count (whatever may be the reason for retry)
3235 3235 *
3236 3236 * Return Values:
3237 3237 * FC_SUCCESS
3238 3238 * FC_FAILURE
3239 3239 */
3240 3240 static int
3241 3241 fp_retry_cmd(fc_packet_t *pkt)
3242 3242 {
3243 3243 fp_cmd_t *cmd;
3244 3244
3245 3245 cmd = pkt->pkt_ulp_private;
3246 3246
3247 3247 if (--cmd->cmd_retry_count) {
3248 3248 fp_enque_cmd(cmd->cmd_port, cmd);
3249 3249 return (FC_SUCCESS);
3250 3250 } else {
3251 3251 return (FC_FAILURE);
3252 3252 }
3253 3253 }
3254 3254
3255 3255
3256 3256 /*
3257 3257 * Queue up FC packet for deferred retry
3258 3258 */
3259 3259 static void
3260 3260 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3261 3261 {
3262 3262 timeout_id_t tid;
3263 3263
3264 3264 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3265 3265
3266 3266 #ifdef DEBUG
3267 3267 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3268 3268 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3269 3269 #endif
3270 3270
3271 3271 mutex_enter(&port->fp_mutex);
3272 3272 if (port->fp_wait_tail) {
3273 3273 port->fp_wait_tail->cmd_next = cmd;
3274 3274 port->fp_wait_tail = cmd;
3275 3275 } else {
3276 3276 ASSERT(port->fp_wait_head == NULL);
3277 3277 port->fp_wait_head = port->fp_wait_tail = cmd;
3278 3278 if (port->fp_wait_tid == NULL) {
3279 3279 mutex_exit(&port->fp_mutex);
3280 3280 tid = timeout(fp_resendcmd, (caddr_t)port,
3281 3281 fp_retry_ticks);
3282 3282 mutex_enter(&port->fp_mutex);
3283 3283 port->fp_wait_tid = tid;
3284 3284 }
3285 3285 }
3286 3286 mutex_exit(&port->fp_mutex);
3287 3287 }
3288 3288
3289 3289
3290 3290 /*
3291 3291 * Handle all RJT codes
3292 3292 */
3293 3293 static int
3294 3294 fp_handle_reject(fc_packet_t *pkt)
3295 3295 {
3296 3296 int rval = FC_FAILURE;
3297 3297 uchar_t next_class;
3298 3298 fp_cmd_t *cmd;
3299 3299 fc_local_port_t *port;
3300 3300
3301 3301 cmd = pkt->pkt_ulp_private;
3302 3302 port = cmd->cmd_port;
3303 3303
3304 3304 switch (pkt->pkt_state) {
3305 3305 case FC_PKT_FABRIC_RJT:
3306 3306 case FC_PKT_NPORT_RJT:
3307 3307 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3308 3308 next_class = fp_get_nextclass(cmd->cmd_port,
3309 3309 FC_TRAN_CLASS(pkt->pkt_tran_flags));
3310 3310
3311 3311 if (next_class == FC_TRAN_CLASS_INVALID) {
3312 3312 return (rval);
3313 3313 }
3314 3314 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3315 3315 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3316 3316
3317 3317 rval = fp_sendcmd(cmd->cmd_port, cmd,
3318 3318 cmd->cmd_port->fp_fca_handle);
3319 3319
3320 3320 if (rval != FC_SUCCESS) {
3321 3321 pkt->pkt_state = FC_PKT_TRAN_ERROR;
3322 3322 }
3323 3323 }
3324 3324 break;
3325 3325
3326 3326 case FC_PKT_LS_RJT:
3327 3327 case FC_PKT_BA_RJT:
3328 3328 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3329 3329 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3330 3330 cmd->cmd_retry_interval = fp_retry_delay;
3331 3331 rval = fp_retry_cmd(pkt);
3332 3332 }
3333 3333 break;
3334 3334
3335 3335 case FC_PKT_FS_RJT:
3336 3336 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
3337 3337 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
3338 3338 (pkt->pkt_expln == 0x00))) {
3339 3339 cmd->cmd_retry_interval = fp_retry_delay;
3340 3340 rval = fp_retry_cmd(pkt);
3341 3341 }
3342 3342 break;
3343 3343
3344 3344 case FC_PKT_LOCAL_RJT:
3345 3345 if (pkt->pkt_reason == FC_REASON_QFULL) {
3346 3346 cmd->cmd_retry_interval = fp_retry_delay;
3347 3347 rval = fp_retry_cmd(pkt);
3348 3348 }
3349 3349 break;
3350 3350
3351 3351 default:
3352 3352 FP_TRACE(FP_NHEAD1(1, 0),
3353 3353 "fp_handle_reject(): Invalid pkt_state");
3354 3354 break;
3355 3355 }
3356 3356
3357 3357 return (rval);
3358 3358 }
3359 3359
3360 3360
3361 3361 /*
3362 3362 * Return the next class of service supported by the FCA
3363 3363 */
3364 3364 static uchar_t
3365 3365 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3366 3366 {
3367 3367 uchar_t next_class;
3368 3368
3369 3369 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3370 3370
3371 3371 switch (cur_class) {
3372 3372 case FC_TRAN_CLASS_INVALID:
3373 3373 if (port->fp_cos & FC_NS_CLASS1) {
3374 3374 next_class = FC_TRAN_CLASS1;
3375 3375 break;
3376 3376 }
3377 3377 /* FALLTHROUGH */
3378 3378
3379 3379 case FC_TRAN_CLASS1:
3380 3380 if (port->fp_cos & FC_NS_CLASS2) {
3381 3381 next_class = FC_TRAN_CLASS2;
3382 3382 break;
3383 3383 }
3384 3384 /* FALLTHROUGH */
3385 3385
3386 3386 case FC_TRAN_CLASS2:
3387 3387 if (port->fp_cos & FC_NS_CLASS3) {
3388 3388 next_class = FC_TRAN_CLASS3;
3389 3389 break;
3390 3390 }
3391 3391 /* FALLTHROUGH */
3392 3392
3393 3393 case FC_TRAN_CLASS3:
3394 3394 default:
3395 3395 next_class = FC_TRAN_CLASS_INVALID;
3396 3396 break;
3397 3397 }
3398 3398
3399 3399 return (next_class);
3400 3400 }
3401 3401
3402 3402
3403 3403 /*
3404 3404 * Determine if a class of service is supported by the FCA
3405 3405 */
3406 3406 static int
3407 3407 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3408 3408 {
3409 3409 int rval;
3410 3410
3411 3411 switch (tran_class) {
3412 3412 case FC_TRAN_CLASS1:
3413 3413 if (cos & FC_NS_CLASS1) {
3414 3414 rval = FC_SUCCESS;
3415 3415 } else {
3416 3416 rval = FC_FAILURE;
3417 3417 }
3418 3418 break;
3419 3419
3420 3420 case FC_TRAN_CLASS2:
3421 3421 if (cos & FC_NS_CLASS2) {
3422 3422 rval = FC_SUCCESS;
3423 3423 } else {
3424 3424 rval = FC_FAILURE;
3425 3425 }
3426 3426 break;
3427 3427
3428 3428 case FC_TRAN_CLASS3:
3429 3429 if (cos & FC_NS_CLASS3) {
3430 3430 rval = FC_SUCCESS;
3431 3431 } else {
3432 3432 rval = FC_FAILURE;
3433 3433 }
3434 3434 break;
3435 3435
3436 3436 default:
3437 3437 rval = FC_FAILURE;
3438 3438 break;
3439 3439 }
3440 3440
3441 3441 return (rval);
3442 3442 }
3443 3443
3444 3444
3445 3445 /*
3446 3446 * Dequeue FC packet for retry
3447 3447 */
3448 3448 static fp_cmd_t *
3449 3449 fp_deque_cmd(fc_local_port_t *port)
3450 3450 {
3451 3451 fp_cmd_t *cmd;
3452 3452
3453 3453 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3454 3454
3455 3455 mutex_enter(&port->fp_mutex);
3456 3456
3457 3457 if (port->fp_wait_head == NULL) {
3458 3458 /*
3459 3459 * To avoid races, NULL the fp_wait_tid as
3460 3460 * we are about to exit the timeout thread.
3461 3461 */
3462 3462 port->fp_wait_tid = NULL;
3463 3463 mutex_exit(&port->fp_mutex);
3464 3464 return (NULL);
3465 3465 }
3466 3466
3467 3467 cmd = port->fp_wait_head;
3468 3468 port->fp_wait_head = cmd->cmd_next;
3469 3469 cmd->cmd_next = NULL;
3470 3470
3471 3471 if (port->fp_wait_head == NULL) {
3472 3472 port->fp_wait_tail = NULL;
3473 3473 }
3474 3474 mutex_exit(&port->fp_mutex);
3475 3475
3476 3476 return (cmd);
3477 3477 }
3478 3478
3479 3479
3480 3480 /*
3481 3481 * Wait for job completion
3482 3482 */
3483 3483 static void
3484 3484 fp_jobwait(job_request_t *job)
3485 3485 {
3486 3486 sema_p(&job->job_port_sema);
3487 3487 }
3488 3488
3489 3489
3490 3490 /*
3491 3491 * Convert FC packet state to FC errno
3492 3492 */
3493 3493 int
3494 3494 fp_state_to_rval(uchar_t state)
3495 3495 {
3496 3496 int count;
3497 3497
3498 3498 for (count = 0; count < sizeof (fp_xlat) /
3499 3499 sizeof (fp_xlat[0]); count++) {
3500 3500 if (fp_xlat[count].xlat_state == state) {
3501 3501 return (fp_xlat[count].xlat_rval);
3502 3502 }
3503 3503 }
3504 3504
3505 3505 return (FC_FAILURE);
3506 3506 }
3507 3507
3508 3508
3509 3509 /*
3510 3510 * For Synchronous I/O requests, the caller is
3511 3511 * expected to do fctl_jobdone(if necessary)
3512 3512 *
3513 3513 * We want to preserve at least one failure in the
3514 3514 * job_result if it happens.
3515 3515 *
3516 3516 */
3517 3517 static void
3518 3518 fp_iodone(fp_cmd_t *cmd)
3519 3519 {
3520 3520 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt;
3521 3521 job_request_t *job = cmd->cmd_job;
3522 3522 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd;
3523 3523
3524 3524 ASSERT(job != NULL);
3525 3525 ASSERT(cmd->cmd_port != NULL);
3526 3526 ASSERT(&cmd->cmd_pkt != NULL);
3527 3527
3528 3528 mutex_enter(&job->job_mutex);
3529 3529 if (job->job_result == FC_SUCCESS) {
3530 3530 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3531 3531 }
3532 3532 mutex_exit(&job->job_mutex);
3533 3533
3534 3534 if (pd) {
3535 3535 mutex_enter(&pd->pd_mutex);
3536 3536 pd->pd_flags = PD_IDLE;
3537 3537 mutex_exit(&pd->pd_mutex);
3538 3538 }
3539 3539
3540 3540 if (ulp_pkt) {
3541 3541 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3542 3542 FP_IS_PKT_ERROR(ulp_pkt)) {
3543 3543 fc_local_port_t *port;
3544 3544 fc_remote_node_t *node;
3545 3545
3546 3546 port = cmd->cmd_port;
3547 3547
3548 3548 mutex_enter(&pd->pd_mutex);
3549 3549 pd->pd_state = PORT_DEVICE_INVALID;
3550 3550 pd->pd_ref_count--;
3551 3551 node = pd->pd_remote_nodep;
3552 3552 mutex_exit(&pd->pd_mutex);
3553 3553
3554 3554 ASSERT(node != NULL);
3555 3555 ASSERT(port != NULL);
3556 3556
3557 3557 if (fctl_destroy_remote_port(port, pd) == 0) {
3558 3558 fctl_destroy_remote_node(node);
3559 3559 }
3560 3560
3561 3561 ulp_pkt->pkt_pd = NULL;
3562 3562 }
3563 3563
3564 3564 ulp_pkt->pkt_comp(ulp_pkt);
3565 3565 }
3566 3566
3567 3567 fp_free_pkt(cmd);
3568 3568 fp_jobdone(job);
3569 3569 }
3570 3570
3571 3571
3572 3572 /*
3573 3573 * Job completion handler
3574 3574 */
3575 3575 static void
3576 3576 fp_jobdone(job_request_t *job)
3577 3577 {
3578 3578 mutex_enter(&job->job_mutex);
3579 3579 ASSERT(job->job_counter > 0);
3580 3580
3581 3581 if (--job->job_counter != 0) {
3582 3582 mutex_exit(&job->job_mutex);
3583 3583 return;
3584 3584 }
3585 3585
3586 3586 if (job->job_ulp_pkts) {
3587 3587 ASSERT(job->job_ulp_listlen > 0);
3588 3588 kmem_free(job->job_ulp_pkts,
3589 3589 sizeof (fc_packet_t *) * job->job_ulp_listlen);
3590 3590 }
3591 3591
3592 3592 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3593 3593 mutex_exit(&job->job_mutex);
3594 3594 fctl_jobdone(job);
3595 3595 } else {
3596 3596 mutex_exit(&job->job_mutex);
3597 3597 sema_v(&job->job_port_sema);
3598 3598 }
3599 3599 }
3600 3600
3601 3601
3602 3602 /*
3603 3603 * Try to perform shutdown of a port during a detach. No return
3604 3604 * value since the detach should not fail because the port shutdown
3605 3605 * failed.
3606 3606 */
3607 3607 static void
3608 3608 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3609 3609 {
3610 3610 int index;
3611 3611 int count;
3612 3612 int flags;
3613 3613 fp_cmd_t *cmd;
3614 3614 struct pwwn_hash *head;
3615 3615 fc_remote_port_t *pd;
3616 3616
3617 3617 ASSERT(MUTEX_HELD(&port->fp_mutex));
3618 3618
3619 3619 job->job_result = FC_SUCCESS;
3620 3620
3621 3621 if (port->fp_taskq) {
3622 3622 /*
3623 3623 * We must release the mutex here to ensure that other
3624 3624 * potential jobs can complete their processing. Many
3625 3625 * also need this mutex.
3626 3626 */
3627 3627 mutex_exit(&port->fp_mutex);
3628 3628 taskq_wait(port->fp_taskq);
3629 3629 mutex_enter(&port->fp_mutex);
3630 3630 }
3631 3631
3632 3632 if (port->fp_offline_tid) {
3633 3633 timeout_id_t tid;
3634 3634
3635 3635 tid = port->fp_offline_tid;
3636 3636 port->fp_offline_tid = NULL;
3637 3637 mutex_exit(&port->fp_mutex);
3638 3638 (void) untimeout(tid);
3639 3639 mutex_enter(&port->fp_mutex);
3640 3640 }
3641 3641
3642 3642 if (port->fp_wait_tid) {
3643 3643 timeout_id_t tid;
3644 3644
3645 3645 tid = port->fp_wait_tid;
3646 3646 port->fp_wait_tid = NULL;
3647 3647 mutex_exit(&port->fp_mutex);
3648 3648 (void) untimeout(tid);
3649 3649 } else {
3650 3650 mutex_exit(&port->fp_mutex);
3651 3651 }
3652 3652
3653 3653 /*
3654 3654 * While we cancel the timeout, let's also return the
3655 3655 * the outstanding requests back to the callers.
3656 3656 */
3657 3657 while ((cmd = fp_deque_cmd(port)) != NULL) {
3658 3658 ASSERT(cmd->cmd_job != NULL);
3659 3659 cmd->cmd_job->job_result = FC_OFFLINE;
3660 3660 fp_iodone(cmd);
3661 3661 }
3662 3662
3663 3663 /*
3664 3664 * Gracefully LOGO with all the devices logged in.
3665 3665 */
3666 3666 mutex_enter(&port->fp_mutex);
3667 3667
3668 3668 for (count = index = 0; index < pwwn_table_size; index++) {
3669 3669 head = &port->fp_pwwn_table[index];
3670 3670 pd = head->pwwn_head;
3671 3671 while (pd != NULL) {
3672 3672 mutex_enter(&pd->pd_mutex);
3673 3673 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3674 3674 count++;
3675 3675 }
3676 3676 mutex_exit(&pd->pd_mutex);
3677 3677 pd = pd->pd_wwn_hnext;
3678 3678 }
3679 3679 }
3680 3680
3681 3681 if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3682 3682 flags = job->job_flags;
3683 3683 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3684 3684 } else {
3685 3685 flags = 0;
3686 3686 }
3687 3687 if (count) {
3688 3688 job->job_counter = count;
3689 3689
3690 3690 for (index = 0; index < pwwn_table_size; index++) {
3691 3691 head = &port->fp_pwwn_table[index];
3692 3692 pd = head->pwwn_head;
3693 3693 while (pd != NULL) {
3694 3694 mutex_enter(&pd->pd_mutex);
3695 3695 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3696 3696 ASSERT(pd->pd_login_count > 0);
3697 3697 /*
3698 3698 * Force the counter to ONE in order
3699 3699 * for us to really send LOGO els.
3700 3700 */
3701 3701 pd->pd_login_count = 1;
3702 3702 mutex_exit(&pd->pd_mutex);
3703 3703 mutex_exit(&port->fp_mutex);
3704 3704 (void) fp_logout(port, pd, job);
3705 3705 mutex_enter(&port->fp_mutex);
3706 3706 } else {
3707 3707 mutex_exit(&pd->pd_mutex);
3708 3708 }
3709 3709 pd = pd->pd_wwn_hnext;
3710 3710 }
3711 3711 }
3712 3712 mutex_exit(&port->fp_mutex);
3713 3713 fp_jobwait(job);
3714 3714 } else {
3715 3715 mutex_exit(&port->fp_mutex);
3716 3716 }
3717 3717
3718 3718 if (job->job_result != FC_SUCCESS) {
3719 3719 FP_TRACE(FP_NHEAD1(9, 0),
3720 3720 "Can't logout all devices. Proceeding with"
3721 3721 " port shutdown");
3722 3722 job->job_result = FC_SUCCESS;
3723 3723 }
3724 3724
3725 3725 fctl_destroy_all_remote_ports(port);
3726 3726
3727 3727 mutex_enter(&port->fp_mutex);
3728 3728 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3729 3729 mutex_exit(&port->fp_mutex);
3730 3730 fp_ns_fini(port, job);
3731 3731 } else {
3732 3732 mutex_exit(&port->fp_mutex);
3733 3733 }
3734 3734
3735 3735 if (flags) {
3736 3736 job->job_flags = flags;
3737 3737 }
3738 3738
3739 3739 mutex_enter(&port->fp_mutex);
3740 3740
3741 3741 }
3742 3742
3743 3743
3744 3744 /*
3745 3745 * Build the port driver's data structures based on the AL_PA list
3746 3746 */
3747 3747 static void
3748 3748 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3749 3749 {
3750 3750 int rval;
3751 3751 int flag;
3752 3752 int count;
3753 3753 uint32_t d_id;
3754 3754 fc_remote_port_t *pd;
3755 3755 fc_lilpmap_t *lilp_map;
3756 3756
3757 3757 ASSERT(MUTEX_HELD(&port->fp_mutex));
3758 3758
3759 3759 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3760 3760 job->job_result = FC_OFFLINE;
3761 3761 mutex_exit(&port->fp_mutex);
3762 3762 fp_jobdone(job);
3763 3763 mutex_enter(&port->fp_mutex);
3764 3764 return;
3765 3765 }
3766 3766
3767 3767 if (port->fp_lilp_map.lilp_length == 0) {
3768 3768 mutex_exit(&port->fp_mutex);
3769 3769 job->job_result = FC_NO_MAP;
3770 3770 fp_jobdone(job);
3771 3771 mutex_enter(&port->fp_mutex);
3772 3772 return;
3773 3773 }
3774 3774 mutex_exit(&port->fp_mutex);
3775 3775
3776 3776 lilp_map = &port->fp_lilp_map;
3777 3777 job->job_counter = lilp_map->lilp_length;
3778 3778
3779 3779 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3780 3780 flag = FP_CMD_PLOGI_RETAIN;
3781 3781 } else {
3782 3782 flag = FP_CMD_PLOGI_DONT_CARE;
3783 3783 }
3784 3784
3785 3785 for (count = 0; count < lilp_map->lilp_length; count++) {
3786 3786 d_id = lilp_map->lilp_alpalist[count];
3787 3787
3788 3788 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3789 3789 fp_jobdone(job);
3790 3790 continue;
3791 3791 }
3792 3792
3793 3793 pd = fctl_get_remote_port_by_did(port, d_id);
3794 3794 if (pd) {
3795 3795 mutex_enter(&pd->pd_mutex);
3796 3796 if (flag == FP_CMD_PLOGI_DONT_CARE ||
3797 3797 pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3798 3798 mutex_exit(&pd->pd_mutex);
3799 3799 fp_jobdone(job);
3800 3800 continue;
3801 3801 }
3802 3802 mutex_exit(&pd->pd_mutex);
3803 3803 }
3804 3804
3805 3805 rval = fp_port_login(port, d_id, job, flag,
3806 3806 KM_SLEEP, pd, NULL);
3807 3807 if (rval != FC_SUCCESS) {
3808 3808 fp_jobdone(job);
3809 3809 }
3810 3810 }
3811 3811
3812 3812 mutex_enter(&port->fp_mutex);
3813 3813 }
3814 3814
3815 3815
3816 3816 /*
3817 3817 * Perform loop ONLINE processing
3818 3818 */
3819 3819 static void
3820 3820 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3821 3821 {
3822 3822 int count;
3823 3823 int rval;
3824 3824 uint32_t d_id;
3825 3825 uint32_t listlen;
3826 3826 fc_lilpmap_t *lilp_map;
3827 3827 fc_remote_port_t *pd;
3828 3828 fc_portmap_t *changelist;
3829 3829
3830 3830 ASSERT(!MUTEX_HELD(&port->fp_mutex));
3831 3831
3832 3832 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3833 3833 port, job);
3834 3834
3835 3835 lilp_map = &port->fp_lilp_map;
3836 3836
3837 3837 if (lilp_map->lilp_length) {
3838 3838 mutex_enter(&port->fp_mutex);
3839 3839 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3840 3840 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3841 3841 mutex_exit(&port->fp_mutex);
3842 3842 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3843 3843 } else {
3844 3844 mutex_exit(&port->fp_mutex);
3845 3845 }
3846 3846
3847 3847 job->job_counter = lilp_map->lilp_length;
3848 3848
3849 3849 for (count = 0; count < lilp_map->lilp_length; count++) {
3850 3850 d_id = lilp_map->lilp_alpalist[count];
3851 3851
3852 3852 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3853 3853 fp_jobdone(job);
3854 3854 continue;
3855 3855 }
3856 3856
3857 3857 pd = fctl_get_remote_port_by_did(port, d_id);
3858 3858 if (pd != NULL) {
3859 3859 #ifdef DEBUG
3860 3860 mutex_enter(&pd->pd_mutex);
3861 3861 if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3862 3862 ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3863 3863 }
3864 3864 mutex_exit(&pd->pd_mutex);
3865 3865 #endif
3866 3866 fp_jobdone(job);
3867 3867 continue;
3868 3868 }
3869 3869
3870 3870 rval = fp_port_login(port, d_id, job,
3871 3871 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3872 3872
3873 3873 if (rval != FC_SUCCESS) {
3874 3874 fp_jobdone(job);
3875 3875 }
3876 3876 }
3877 3877 fp_jobwait(job);
3878 3878 }
3879 3879 listlen = 0;
3880 3880 changelist = NULL;
3881 3881
3882 3882 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3883 3883 mutex_enter(&port->fp_mutex);
3884 3884 ASSERT(port->fp_statec_busy > 0);
3885 3885 if (port->fp_statec_busy == 1) {
3886 3886 mutex_exit(&port->fp_mutex);
3887 3887 fctl_fillout_map(port, &changelist, &listlen,
3888 3888 1, 0, orphan);
3889 3889
3890 3890 mutex_enter(&port->fp_mutex);
3891 3891 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3892 3892 ASSERT(port->fp_total_devices == 0);
3893 3893 port->fp_total_devices = port->fp_dev_count;
3894 3894 }
3895 3895 } else {
3896 3896 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3897 3897 }
3898 3898 mutex_exit(&port->fp_mutex);
3899 3899 }
3900 3900
3901 3901 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3902 3902 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3903 3903 listlen, listlen, KM_SLEEP);
3904 3904 } else {
3905 3905 mutex_enter(&port->fp_mutex);
3906 3906 if (--port->fp_statec_busy == 0) {
3907 3907 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3908 3908 }
3909 3909 ASSERT(changelist == NULL && listlen == 0);
3910 3910 mutex_exit(&port->fp_mutex);
3911 3911 }
3912 3912
3913 3913 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3914 3914 port, job);
3915 3915 }
3916 3916
3917 3917
3918 3918 /*
3919 3919 * Get an Arbitrated Loop map from the underlying FCA
3920 3920 */
3921 3921 static int
3922 3922 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3923 3923 {
3924 3924 int rval;
3925 3925
3926 3926 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3927 3927 port, lilp_map);
3928 3928
3929 3929 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3930 3930 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3931 3931 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */
3932 3932
3933 3933 if (rval != FC_SUCCESS) {
3934 3934 rval = FC_NO_MAP;
3935 3935 } else if (lilp_map->lilp_length == 0 &&
3936 3936 (lilp_map->lilp_magic >= MAGIC_LISM &&
3937 3937 lilp_map->lilp_magic < MAGIC_LIRP)) {
3938 3938 uchar_t lilp_length;
3939 3939
3940 3940 /*
3941 3941 * Since the map length is zero, provide all
3942 3942 * the valid AL_PAs for NL_ports discovery.
3943 3943 */
3944 3944 lilp_length = sizeof (fp_valid_alpas) /
3945 3945 sizeof (fp_valid_alpas[0]);
3946 3946 lilp_map->lilp_length = lilp_length;
3947 3947 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3948 3948 lilp_length);
3949 3949 } else {
3950 3950 rval = fp_validate_lilp_map(lilp_map);
3951 3951
3952 3952 if (rval == FC_SUCCESS) {
3953 3953 mutex_enter(&port->fp_mutex);
3954 3954 port->fp_total_devices = lilp_map->lilp_length - 1;
3955 3955 mutex_exit(&port->fp_mutex);
3956 3956 }
3957 3957 }
3958 3958
3959 3959 mutex_enter(&port->fp_mutex);
3960 3960 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3961 3961 port->fp_soft_state |= FP_SOFT_BAD_LINK;
3962 3962 mutex_exit(&port->fp_mutex);
3963 3963
3964 3964 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3965 3965 FC_FCA_RESET_CORE) != FC_SUCCESS) {
3966 3966 FP_TRACE(FP_NHEAD1(9, 0),
3967 3967 "FCA reset failed after LILP map was found"
3968 3968 " to be invalid");
3969 3969 }
3970 3970 } else if (rval == FC_SUCCESS) {
3971 3971 port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3972 3972 mutex_exit(&port->fp_mutex);
3973 3973 } else {
3974 3974 mutex_exit(&port->fp_mutex);
3975 3975 }
3976 3976
3977 3977 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3978 3978 lilp_map);
3979 3979
3980 3980 return (rval);
3981 3981 }
3982 3982
3983 3983
3984 3984 /*
3985 3985 * Perform Fabric Login:
3986 3986 *
3987 3987 * Return Values:
3988 3988 * FC_SUCCESS
3989 3989 * FC_FAILURE
3990 3990 * FC_NOMEM
3991 3991 * FC_TRANSPORT_ERROR
3992 3992 * and a lot others defined in fc_error.h
3993 3993 */
3994 3994 static int
3995 3995 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3996 3996 int flag, int sleep)
3997 3997 {
3998 3998 int rval;
3999 3999 fp_cmd_t *cmd;
4000 4000 uchar_t class;
4001 4001
4002 4002 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4003 4003
4004 4004 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
4005 4005 port, job);
4006 4006
4007 4007 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4008 4008 if (class == FC_TRAN_CLASS_INVALID) {
4009 4009 return (FC_ELS_BAD);
4010 4010 }
4011 4011
4012 4012 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4013 4013 sizeof (la_els_logi_t), sleep, NULL);
4014 4014 if (cmd == NULL) {
4015 4015 return (FC_NOMEM);
4016 4016 }
4017 4017
4018 4018 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4019 4019 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4020 4020 cmd->cmd_flags = flag;
4021 4021 cmd->cmd_retry_count = fp_retry_count;
4022 4022 cmd->cmd_ulp_pkt = NULL;
4023 4023
4024 4024 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
4025 4025 job, LA_ELS_FLOGI);
4026 4026
4027 4027 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
4028 4028 if (rval != FC_SUCCESS) {
4029 4029 fp_free_pkt(cmd);
4030 4030 }
4031 4031
4032 4032 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
4033 4033 port, job);
4034 4034
4035 4035 return (rval);
4036 4036 }
4037 4037
4038 4038
4039 4039 /*
4040 4040 * In some scenarios such as private loop device discovery period
4041 4041 * the fc_remote_port_t data structure isn't allocated. The allocation
4042 4042 * is done when the PLOGI is successful. In some other scenarios
4043 4043 * such as Fabric topology, the fc_remote_port_t is already created
4044 4044 * and initialized with appropriate values (as the NS provides
4045 4045 * them)
4046 4046 */
4047 4047 static int
4048 4048 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
4049 4049 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
4050 4050 {
4051 4051 uchar_t class;
4052 4052 fp_cmd_t *cmd;
4053 4053 uint32_t src_id;
4054 4054 fc_remote_port_t *tmp_pd;
4055 4055 int relogin;
4056 4056 int found = 0;
4057 4057
4058 4058 #ifdef DEBUG
4059 4059 if (pd == NULL) {
4060 4060 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
4061 4061 }
4062 4062 #endif
4063 4063 ASSERT(job->job_counter > 0);
4064 4064
4065 4065 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4066 4066 if (class == FC_TRAN_CLASS_INVALID) {
4067 4067 return (FC_ELS_BAD);
4068 4068 }
4069 4069
4070 4070 mutex_enter(&port->fp_mutex);
4071 4071 tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4072 4072 mutex_exit(&port->fp_mutex);
4073 4073
4074 4074 relogin = 1;
4075 4075 if (tmp_pd) {
4076 4076 mutex_enter(&tmp_pd->pd_mutex);
4077 4077 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4078 4078 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4079 4079 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4080 4080 relogin = 0;
4081 4081 }
4082 4082 mutex_exit(&tmp_pd->pd_mutex);
4083 4083 }
4084 4084
4085 4085 if (!relogin) {
4086 4086 mutex_enter(&tmp_pd->pd_mutex);
4087 4087 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4088 4088 cmd_flag |= FP_CMD_PLOGI_RETAIN;
4089 4089 }
4090 4090 mutex_exit(&tmp_pd->pd_mutex);
4091 4091
4092 4092 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4093 4093 sizeof (la_els_adisc_t), sleep, tmp_pd);
4094 4094 if (cmd == NULL) {
4095 4095 return (FC_NOMEM);
4096 4096 }
4097 4097
4098 4098 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4099 4099 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4100 4100 cmd->cmd_flags = cmd_flag;
4101 4101 cmd->cmd_retry_count = fp_retry_count;
4102 4102 cmd->cmd_ulp_pkt = ulp_pkt;
4103 4103
4104 4104 mutex_enter(&port->fp_mutex);
4105 4105 mutex_enter(&tmp_pd->pd_mutex);
4106 4106 fp_adisc_init(cmd, job);
4107 4107 mutex_exit(&tmp_pd->pd_mutex);
4108 4108 mutex_exit(&port->fp_mutex);
4109 4109
4110 4110 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4111 4111 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4112 4112
4113 4113 } else {
4114 4114 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4115 4115 sizeof (la_els_logi_t), sleep, pd);
4116 4116 if (cmd == NULL) {
4117 4117 return (FC_NOMEM);
4118 4118 }
4119 4119
4120 4120 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4121 4121 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4122 4122 cmd->cmd_flags = cmd_flag;
4123 4123 cmd->cmd_retry_count = fp_retry_count;
4124 4124 cmd->cmd_ulp_pkt = ulp_pkt;
4125 4125
4126 4126 mutex_enter(&port->fp_mutex);
4127 4127 src_id = port->fp_port_id.port_id;
4128 4128 mutex_exit(&port->fp_mutex);
4129 4129
4130 4130 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4131 4131 job, LA_ELS_PLOGI);
4132 4132 }
4133 4133
4134 4134 if (pd) {
4135 4135 mutex_enter(&pd->pd_mutex);
4136 4136 pd->pd_flags = PD_ELS_IN_PROGRESS;
4137 4137 mutex_exit(&pd->pd_mutex);
4138 4138 }
4139 4139
4140 4140 /* npiv check to make sure we don't log into ourself */
4141 4141 if (relogin &&
4142 4142 ((port->fp_npiv_type == FC_NPIV_PORT) ||
4143 4143 (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
4144 4144 if ((d_id & 0xffff00) ==
4145 4145 (port->fp_port_id.port_id & 0xffff00)) {
4146 4146 found = 1;
4147 4147 }
4148 4148 }
4149 4149
4150 4150 if (found ||
4151 4151 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4152 4152 if (found) {
4153 4153 fc_packet_t *pkt = &cmd->cmd_pkt;
4154 4154 pkt->pkt_state = FC_PKT_NPORT_RJT;
4155 4155 }
4156 4156 if (pd) {
4157 4157 mutex_enter(&pd->pd_mutex);
4158 4158 pd->pd_flags = PD_IDLE;
4159 4159 mutex_exit(&pd->pd_mutex);
4160 4160 }
4161 4161
4162 4162 if (ulp_pkt) {
4163 4163 fc_packet_t *pkt = &cmd->cmd_pkt;
4164 4164
4165 4165 ulp_pkt->pkt_state = pkt->pkt_state;
4166 4166 ulp_pkt->pkt_reason = pkt->pkt_reason;
4167 4167 ulp_pkt->pkt_action = pkt->pkt_action;
4168 4168 ulp_pkt->pkt_expln = pkt->pkt_expln;
4169 4169 }
4170 4170
4171 4171 fp_iodone(cmd);
4172 4172 }
4173 4173
4174 4174 return (FC_SUCCESS);
4175 4175 }
4176 4176
4177 4177
4178 4178 /*
4179 4179 * Register the LOGIN parameters with a port device
4180 4180 */
4181 4181 static void
4182 4182 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4183 4183 la_els_logi_t *acc, uchar_t class)
4184 4184 {
4185 4185 fc_remote_node_t *node;
4186 4186
4187 4187 ASSERT(pd != NULL);
4188 4188
4189 4189 mutex_enter(&pd->pd_mutex);
4190 4190 node = pd->pd_remote_nodep;
4191 4191 if (pd->pd_login_count == 0) {
4192 4192 pd->pd_login_count++;
4193 4193 }
4194 4194
4195 4195 if (handle) {
4196 4196 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
4197 4197 (uint8_t *)&acc->common_service,
4198 4198 sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4199 4199 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
4200 4200 (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4201 4201 DDI_DEV_AUTOINCR);
4202 4202 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
4203 4203 (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4204 4204 DDI_DEV_AUTOINCR);
4205 4205 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
4206 4206 (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4207 4207 DDI_DEV_AUTOINCR);
4208 4208 } else {
4209 4209 pd->pd_csp = acc->common_service;
4210 4210 pd->pd_clsp1 = acc->class_1;
4211 4211 pd->pd_clsp2 = acc->class_2;
4212 4212 pd->pd_clsp3 = acc->class_3;
4213 4213 }
4214 4214
4215 4215 pd->pd_state = PORT_DEVICE_LOGGED_IN;
4216 4216 pd->pd_login_class = class;
4217 4217 mutex_exit(&pd->pd_mutex);
4218 4218
4219 4219 #ifndef __lock_lint
4220 4220 ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4221 4221 pd->pd_port_id.port_id) == pd);
4222 4222 #endif
4223 4223
4224 4224 mutex_enter(&node->fd_mutex);
4225 4225 if (handle) {
4226 4226 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
4227 4227 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4228 4228 DDI_DEV_AUTOINCR);
4229 4229 } else {
4230 4230 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4231 4231 }
4232 4232 mutex_exit(&node->fd_mutex);
4233 4233 }
4234 4234
4235 4235
4236 4236 /*
4237 4237 * Mark the remote port as OFFLINE
4238 4238 */
4239 4239 static void
4240 4240 fp_remote_port_offline(fc_remote_port_t *pd)
4241 4241 {
4242 4242 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4243 4243 if (pd->pd_login_count &&
4244 4244 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4245 4245 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4246 4246 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4247 4247 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4248 4248 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4249 4249 pd->pd_login_class = 0;
4250 4250 }
4251 4251 pd->pd_type = PORT_DEVICE_OLD;
4252 4252 pd->pd_flags = PD_IDLE;
4253 4253 fctl_tc_reset(&pd->pd_logo_tc);
4254 4254 }
4255 4255
4256 4256
4257 4257 /*
4258 4258 * Deregistration of a port device
4259 4259 */
4260 4260 static void
4261 4261 fp_unregister_login(fc_remote_port_t *pd)
4262 4262 {
4263 4263 fc_remote_node_t *node;
4264 4264
4265 4265 ASSERT(pd != NULL);
4266 4266
4267 4267 mutex_enter(&pd->pd_mutex);
4268 4268 pd->pd_login_count = 0;
4269 4269 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4270 4270 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4271 4271 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4272 4272 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4273 4273
4274 4274 pd->pd_state = PORT_DEVICE_VALID;
4275 4275 pd->pd_login_class = 0;
4276 4276 node = pd->pd_remote_nodep;
4277 4277 mutex_exit(&pd->pd_mutex);
4278 4278
4279 4279 mutex_enter(&node->fd_mutex);
4280 4280 bzero(node->fd_vv, sizeof (node->fd_vv));
4281 4281 mutex_exit(&node->fd_mutex);
4282 4282 }
4283 4283
4284 4284
4285 4285 /*
4286 4286 * Handle OFFLINE state of an FCA port
4287 4287 */
4288 4288 static void
4289 4289 fp_port_offline(fc_local_port_t *port, int notify)
4290 4290 {
4291 4291 int index;
4292 4292 int statec;
4293 4293 timeout_id_t tid;
4294 4294 struct pwwn_hash *head;
4295 4295 fc_remote_port_t *pd;
4296 4296
4297 4297 ASSERT(MUTEX_HELD(&port->fp_mutex));
4298 4298
4299 4299 for (index = 0; index < pwwn_table_size; index++) {
4300 4300 head = &port->fp_pwwn_table[index];
4301 4301 pd = head->pwwn_head;
4302 4302 while (pd != NULL) {
4303 4303 mutex_enter(&pd->pd_mutex);
4304 4304 fp_remote_port_offline(pd);
4305 4305 fctl_delist_did_table(port, pd);
4306 4306 mutex_exit(&pd->pd_mutex);
4307 4307 pd = pd->pd_wwn_hnext;
4308 4308 }
4309 4309 }
4310 4310 port->fp_total_devices = 0;
4311 4311
4312 4312 statec = 0;
4313 4313 if (notify) {
4314 4314 /*
4315 4315 * Decrement the statec busy counter as we
4316 4316 * are almost done with handling the state
4317 4317 * change
4318 4318 */
4319 4319 ASSERT(port->fp_statec_busy > 0);
4320 4320 if (--port->fp_statec_busy == 0) {
4321 4321 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4322 4322 }
4323 4323 mutex_exit(&port->fp_mutex);
4324 4324 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4325 4325 0, 0, KM_SLEEP);
4326 4326 mutex_enter(&port->fp_mutex);
4327 4327
4328 4328 if (port->fp_statec_busy) {
4329 4329 statec++;
4330 4330 }
4331 4331 } else if (port->fp_statec_busy > 1) {
4332 4332 statec++;
4333 4333 }
4334 4334
4335 4335 if ((tid = port->fp_offline_tid) != NULL) {
4336 4336 mutex_exit(&port->fp_mutex);
4337 4337 (void) untimeout(tid);
4338 4338 mutex_enter(&port->fp_mutex);
4339 4339 }
4340 4340
4341 4341 if (!statec) {
4342 4342 port->fp_offline_tid = timeout(fp_offline_timeout,
4343 4343 (caddr_t)port, fp_offline_ticks);
4344 4344 }
4345 4345 }
4346 4346
4347 4347
4348 4348 /*
4349 4349 * Offline devices and send up a state change notification to ULPs
4350 4350 */
4351 4351 static void
4352 4352 fp_offline_timeout(void *port_handle)
4353 4353 {
4354 4354 int ret;
4355 4355 fc_local_port_t *port = port_handle;
4356 4356 uint32_t listlen = 0;
4357 4357 fc_portmap_t *changelist = NULL;
4358 4358
4359 4359 mutex_enter(&port->fp_mutex);
4360 4360
4361 4361 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4362 4362 (port->fp_soft_state &
4363 4363 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4364 4364 port->fp_dev_count == 0 || port->fp_statec_busy) {
4365 4365 port->fp_offline_tid = NULL;
4366 4366 mutex_exit(&port->fp_mutex);
4367 4367 return;
4368 4368 }
4369 4369
4370 4370 mutex_exit(&port->fp_mutex);
4371 4371
4372 4372 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4373 4373
4374 4374 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4375 4375 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4376 4376 FC_FCA_CORE)) != FC_SUCCESS) {
4377 4377 FP_TRACE(FP_NHEAD1(9, ret),
4378 4378 "Failed to force adapter dump");
4379 4379 } else {
4380 4380 FP_TRACE(FP_NHEAD1(9, 0),
4381 4381 "Forced adapter dump successfully");
4382 4382 }
4383 4383 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4384 4384 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4385 4385 FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4386 4386 FP_TRACE(FP_NHEAD1(9, ret),
4387 4387 "Failed to force adapter dump and reset");
4388 4388 } else {
4389 4389 FP_TRACE(FP_NHEAD1(9, 0),
4390 4390 "Forced adapter dump and reset successfully");
4391 4391 }
4392 4392 }
4393 4393
4394 4394 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4395 4395 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4396 4396 listlen, listlen, KM_SLEEP);
4397 4397
4398 4398 mutex_enter(&port->fp_mutex);
4399 4399 port->fp_offline_tid = NULL;
4400 4400 mutex_exit(&port->fp_mutex);
4401 4401 }
4402 4402
4403 4403
4404 4404 /*
4405 4405 * Perform general purpose ELS request initialization
4406 4406 */
4407 4407 static void
4408 4408 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4409 4409 void (*comp) (), job_request_t *job)
4410 4410 {
4411 4411 fc_packet_t *pkt;
4412 4412
4413 4413 pkt = &cmd->cmd_pkt;
4414 4414 cmd->cmd_job = job;
4415 4415
4416 4416 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4417 4417 pkt->pkt_cmd_fhdr.d_id = d_id;
4418 4418 pkt->pkt_cmd_fhdr.s_id = s_id;
4419 4419 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4420 4420 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4421 4421 pkt->pkt_cmd_fhdr.seq_id = 0;
4422 4422 pkt->pkt_cmd_fhdr.df_ctl = 0;
4423 4423 pkt->pkt_cmd_fhdr.seq_cnt = 0;
4424 4424 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4425 4425 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4426 4426 pkt->pkt_cmd_fhdr.ro = 0;
4427 4427 pkt->pkt_cmd_fhdr.rsvd = 0;
4428 4428 pkt->pkt_comp = comp;
4429 4429 pkt->pkt_timeout = FP_ELS_TIMEOUT;
4430 4430 }
4431 4431
4432 4432
4433 4433 /*
4434 4434 * Initialize PLOGI/FLOGI ELS request
4435 4435 */
4436 4436 static void
4437 4437 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4438 4438 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4439 4439 {
4440 4440 ls_code_t payload;
4441 4441
4442 4442 fp_els_init(cmd, s_id, d_id, intr, job);
4443 4443 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4444 4444
4445 4445 payload.ls_code = ls_code;
4446 4446 payload.mbz = 0;
4447 4447
4448 4448 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
4449 4449 (uint8_t *)&port->fp_service_params,
4450 4450 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4451 4451 DDI_DEV_AUTOINCR);
4452 4452
4453 4453 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4454 4454 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4455 4455 DDI_DEV_AUTOINCR);
4456 4456 }
4457 4457
4458 4458
4459 4459 /*
4460 4460 * Initialize LOGO ELS request
4461 4461 */
4462 4462 static void
4463 4463 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4464 4464 {
4465 4465 fc_local_port_t *port;
4466 4466 fc_packet_t *pkt;
4467 4467 la_els_logo_t payload;
4468 4468
4469 4469 port = pd->pd_port;
4470 4470 pkt = &cmd->cmd_pkt;
4471 4471 ASSERT(MUTEX_HELD(&port->fp_mutex));
4472 4472 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4473 4473
4474 4474 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4475 4475 fp_logo_intr, job);
4476 4476
4477 4477 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4478 4478
4479 4479 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4480 4480 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4481 4481
4482 4482 payload.ls_code.ls_code = LA_ELS_LOGO;
4483 4483 payload.ls_code.mbz = 0;
4484 4484 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4485 4485 payload.nport_id = port->fp_port_id;
4486 4486
4487 4487 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4488 4488 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4489 4489 }
4490 4490
4491 4491 /*
4492 4492 * Initialize RNID ELS request
4493 4493 */
4494 4494 static void
4495 4495 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4496 4496 {
4497 4497 fc_local_port_t *port;
4498 4498 fc_packet_t *pkt;
4499 4499 la_els_rnid_t payload;
4500 4500 fc_remote_port_t *pd;
4501 4501
4502 4502 pkt = &cmd->cmd_pkt;
4503 4503 pd = pkt->pkt_pd;
4504 4504 port = pd->pd_port;
4505 4505
4506 4506 ASSERT(MUTEX_HELD(&port->fp_mutex));
4507 4507 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4508 4508
4509 4509 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4510 4510 fp_rnid_intr, job);
4511 4511
4512 4512 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4513 4513 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4514 4514 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4515 4515
4516 4516 payload.ls_code.ls_code = LA_ELS_RNID;
4517 4517 payload.ls_code.mbz = 0;
4518 4518 payload.data_format = flag;
4519 4519
4520 4520 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4521 4521 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4522 4522 }
4523 4523
4524 4524 /*
4525 4525 * Initialize RLS ELS request
4526 4526 */
4527 4527 static void
4528 4528 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4529 4529 {
4530 4530 fc_local_port_t *port;
4531 4531 fc_packet_t *pkt;
4532 4532 la_els_rls_t payload;
4533 4533 fc_remote_port_t *pd;
4534 4534
4535 4535 pkt = &cmd->cmd_pkt;
4536 4536 pd = pkt->pkt_pd;
4537 4537 port = pd->pd_port;
4538 4538
4539 4539 ASSERT(MUTEX_HELD(&port->fp_mutex));
4540 4540 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4541 4541
4542 4542 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4543 4543 fp_rls_intr, job);
4544 4544
4545 4545 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4546 4546 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4547 4547 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4548 4548
4549 4549 payload.ls_code.ls_code = LA_ELS_RLS;
4550 4550 payload.ls_code.mbz = 0;
4551 4551 payload.rls_portid = port->fp_port_id;
4552 4552
4553 4553 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4554 4554 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4555 4555 }
4556 4556
4557 4557
4558 4558 /*
4559 4559 * Initialize an ADISC ELS request
4560 4560 */
4561 4561 static void
4562 4562 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4563 4563 {
4564 4564 fc_local_port_t *port;
4565 4565 fc_packet_t *pkt;
4566 4566 la_els_adisc_t payload;
4567 4567 fc_remote_port_t *pd;
4568 4568
4569 4569 pkt = &cmd->cmd_pkt;
4570 4570 pd = pkt->pkt_pd;
4571 4571 port = pd->pd_port;
4572 4572
4573 4573 ASSERT(MUTEX_HELD(&pd->pd_mutex));
4574 4574 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4575 4575
4576 4576 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4577 4577 fp_adisc_intr, job);
4578 4578
4579 4579 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4580 4580 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4581 4581 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4582 4582
4583 4583 payload.ls_code.ls_code = LA_ELS_ADISC;
4584 4584 payload.ls_code.mbz = 0;
4585 4585 payload.nport_id = port->fp_port_id;
4586 4586 payload.port_wwn = port->fp_service_params.nport_ww_name;
4587 4587 payload.node_wwn = port->fp_service_params.node_ww_name;
4588 4588 payload.hard_addr = port->fp_hard_addr;
4589 4589
4590 4590 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4591 4591 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4592 4592 }
4593 4593
4594 4594
4595 4595 /*
4596 4596 * Send up a state change notification to ULPs.
4597 4597 * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4598 4598 */
4599 4599 static int
4600 4600 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4601 4601 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4602 4602 {
4603 4603 fc_port_clist_t *clist;
4604 4604 fc_remote_port_t *pd;
4605 4605 int count;
4606 4606
4607 4607 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4608 4608
4609 4609 clist = kmem_zalloc(sizeof (*clist), sleep);
4610 4610 if (clist == NULL) {
4611 4611 kmem_free(changelist, alloc_len * sizeof (*changelist));
4612 4612 return (FC_NOMEM);
4613 4613 }
4614 4614
4615 4615 clist->clist_state = state;
4616 4616
4617 4617 mutex_enter(&port->fp_mutex);
4618 4618 clist->clist_flags = port->fp_topology;
4619 4619 mutex_exit(&port->fp_mutex);
4620 4620
4621 4621 clist->clist_port = (opaque_t)port;
4622 4622 clist->clist_len = listlen;
4623 4623 clist->clist_size = alloc_len;
4624 4624 clist->clist_map = changelist;
4625 4625
4626 4626 /*
4627 4627 * Bump the reference count of each fc_remote_port_t in this changelist.
4628 4628 * This is necessary since these devices will be sitting in a taskq
4629 4629 * and referenced later. When the state change notification is
4630 4630 * complete, the reference counts will be decremented.
4631 4631 */
4632 4632 for (count = 0; count < clist->clist_len; count++) {
4633 4633 pd = clist->clist_map[count].map_pd;
4634 4634
4635 4635 if (pd != NULL) {
4636 4636 mutex_enter(&pd->pd_mutex);
4637 4637 ASSERT((pd->pd_ref_count >= 0) ||
4638 4638 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4639 4639 pd->pd_ref_count++;
4640 4640
4641 4641 if (clist->clist_map[count].map_state !=
4642 4642 PORT_DEVICE_INVALID) {
4643 4643 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4644 4644 }
4645 4645
4646 4646 mutex_exit(&pd->pd_mutex);
4647 4647 }
4648 4648 }
4649 4649
4650 4650 #ifdef DEBUG
4651 4651 /*
4652 4652 * Sanity check for presence of OLD devices in the hash lists
4653 4653 */
4654 4654 if (clist->clist_size) {
4655 4655 ASSERT(clist->clist_map != NULL);
4656 4656 for (count = 0; count < clist->clist_len; count++) {
4657 4657 if (clist->clist_map[count].map_state ==
4658 4658 PORT_DEVICE_INVALID) {
4659 4659 la_wwn_t pwwn;
4660 4660 fc_portid_t d_id;
4661 4661
4662 4662 pd = clist->clist_map[count].map_pd;
4663 4663 ASSERT(pd != NULL);
4664 4664
4665 4665 mutex_enter(&pd->pd_mutex);
4666 4666 pwwn = pd->pd_port_name;
4667 4667 d_id = pd->pd_port_id;
4668 4668 mutex_exit(&pd->pd_mutex);
4669 4669
4670 4670 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4671 4671 ASSERT(pd != clist->clist_map[count].map_pd);
4672 4672
4673 4673 pd = fctl_get_remote_port_by_did(port,
4674 4674 d_id.port_id);
4675 4675 ASSERT(pd != clist->clist_map[count].map_pd);
4676 4676 }
4677 4677 }
4678 4678 }
4679 4679 #endif
4680 4680
4681 4681 mutex_enter(&port->fp_mutex);
4682 4682
4683 4683 if (state == FC_STATE_ONLINE) {
4684 4684 if (--port->fp_statec_busy == 0) {
4685 4685 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4686 4686 }
4687 4687 }
4688 4688 mutex_exit(&port->fp_mutex);
4689 4689
4690 4690 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4691 4691 clist, KM_SLEEP);
4692 4692
4693 4693 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4694 4694 "state=%x, len=%d", port, state, listlen);
4695 4695
4696 4696 return (FC_SUCCESS);
4697 4697 }
4698 4698
4699 4699
4700 4700 /*
4701 4701 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4702 4702 */
4703 4703 static int
4704 4704 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4705 4705 uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4706 4706 {
4707 4707 int ret;
4708 4708 fc_port_clist_t *clist;
4709 4709
4710 4710 ASSERT(!MUTEX_HELD(&port->fp_mutex));
4711 4711
4712 4712 clist = kmem_zalloc(sizeof (*clist), sleep);
4713 4713 if (clist == NULL) {
4714 4714 kmem_free(changelist, alloc_len * sizeof (*changelist));
4715 4715 return (FC_NOMEM);
4716 4716 }
4717 4717
4718 4718 clist->clist_state = FC_STATE_DEVICE_CHANGE;
4719 4719
4720 4720 mutex_enter(&port->fp_mutex);
4721 4721 clist->clist_flags = port->fp_topology;
4722 4722 mutex_exit(&port->fp_mutex);
4723 4723
4724 4724 clist->clist_port = (opaque_t)port;
4725 4725 clist->clist_len = listlen;
4726 4726 clist->clist_size = alloc_len;
4727 4727 clist->clist_map = changelist;
4728 4728
4729 4729 /* Send sysevents for target state changes */
4730 4730
4731 4731 if (clist->clist_size) {
4732 4732 int count;
4733 4733 fc_remote_port_t *pd;
4734 4734
4735 4735 ASSERT(clist->clist_map != NULL);
4736 4736 for (count = 0; count < clist->clist_len; count++) {
4737 4737 pd = clist->clist_map[count].map_pd;
4738 4738
4739 4739 /*
4740 4740 * Bump reference counts on all fc_remote_port_t
4741 4741 * structs in this list. We don't know when the task
4742 4742 * will fire, and we don't need these fc_remote_port_t
4743 4743 * structs going away behind our back.
4744 4744 */
4745 4745 if (pd) {
4746 4746 mutex_enter(&pd->pd_mutex);
4747 4747 ASSERT((pd->pd_ref_count >= 0) ||
4748 4748 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4749 4749 pd->pd_ref_count++;
4750 4750 mutex_exit(&pd->pd_mutex);
4751 4751 }
4752 4752
4753 4753 if (clist->clist_map[count].map_state ==
4754 4754 PORT_DEVICE_VALID) {
4755 4755 if (clist->clist_map[count].map_type ==
4756 4756 PORT_DEVICE_NEW) {
4757 4757 /* Update our state change counter */
4758 4758 mutex_enter(&port->fp_mutex);
4759 4759 port->fp_last_change++;
4760 4760 mutex_exit(&port->fp_mutex);
4761 4761
4762 4762 /* Additions */
4763 4763 fp_log_target_event(port,
4764 4764 ESC_SUNFC_TARGET_ADD,
4765 4765 clist->clist_map[count].map_pwwn,
4766 4766 clist->clist_map[count].map_did.
4767 4767 port_id);
4768 4768 }
4769 4769
4770 4770 } else if ((clist->clist_map[count].map_type ==
4771 4771 PORT_DEVICE_OLD) &&
4772 4772 (clist->clist_map[count].map_state ==
4773 4773 PORT_DEVICE_INVALID)) {
4774 4774 /* Update our state change counter */
4775 4775 mutex_enter(&port->fp_mutex);
4776 4776 port->fp_last_change++;
4777 4777 mutex_exit(&port->fp_mutex);
4778 4778
4779 4779 /*
4780 4780 * For removals, we don't decrement
4781 4781 * pd_ref_count until after the ULP's
4782 4782 * state change callback function has
4783 4783 * completed.
4784 4784 */
4785 4785
4786 4786 /* Removals */
4787 4787 fp_log_target_event(port,
4788 4788 ESC_SUNFC_TARGET_REMOVE,
4789 4789 clist->clist_map[count].map_pwwn,
4790 4790 clist->clist_map[count].map_did.port_id);
4791 4791 }
4792 4792
4793 4793 if (clist->clist_map[count].map_state !=
4794 4794 PORT_DEVICE_INVALID) {
4795 4795 /*
4796 4796 * Indicate that the ULPs are now aware of
4797 4797 * this device.
4798 4798 */
4799 4799
4800 4800 mutex_enter(&pd->pd_mutex);
4801 4801 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4802 4802 mutex_exit(&pd->pd_mutex);
4803 4803 }
4804 4804
4805 4805 #ifdef DEBUG
4806 4806 /*
4807 4807 * Sanity check for OLD devices in the hash lists
4808 4808 */
4809 4809 if (pd && clist->clist_map[count].map_state ==
4810 4810 PORT_DEVICE_INVALID) {
4811 4811 la_wwn_t pwwn;
4812 4812 fc_portid_t d_id;
4813 4813
4814 4814 mutex_enter(&pd->pd_mutex);
4815 4815 pwwn = pd->pd_port_name;
4816 4816 d_id = pd->pd_port_id;
4817 4817 mutex_exit(&pd->pd_mutex);
4818 4818
4819 4819 /*
4820 4820 * This overwrites the 'pd' local variable.
4821 4821 * Beware of this if 'pd' ever gets
4822 4822 * referenced below this block.
4823 4823 */
4824 4824 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4825 4825 ASSERT(pd != clist->clist_map[count].map_pd);
4826 4826
4827 4827 pd = fctl_get_remote_port_by_did(port,
4828 4828 d_id.port_id);
4829 4829 ASSERT(pd != clist->clist_map[count].map_pd);
4830 4830 }
4831 4831 #endif
4832 4832 }
4833 4833 }
4834 4834
4835 4835 if (sync) {
4836 4836 clist->clist_wait = 1;
4837 4837 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4838 4838 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4839 4839 }
4840 4840
4841 4841 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4842 4842 if (sync && ret) {
4843 4843 mutex_enter(&clist->clist_mutex);
4844 4844 while (clist->clist_wait) {
4845 4845 cv_wait(&clist->clist_cv, &clist->clist_mutex);
4846 4846 }
4847 4847 mutex_exit(&clist->clist_mutex);
4848 4848
4849 4849 mutex_destroy(&clist->clist_mutex);
4850 4850 cv_destroy(&clist->clist_cv);
4851 4851 kmem_free(clist, sizeof (*clist));
4852 4852 }
4853 4853
4854 4854 if (!ret) {
4855 4855 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4856 4856 "port=%p", port);
4857 4857 kmem_free(clist->clist_map,
4858 4858 sizeof (*(clist->clist_map)) * clist->clist_size);
4859 4859 kmem_free(clist, sizeof (*clist));
4860 4860 } else {
4861 4861 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4862 4862 port, listlen);
4863 4863 }
4864 4864
4865 4865 return (FC_SUCCESS);
4866 4866 }
4867 4867
4868 4868
4869 4869 /*
4870 4870 * Perform PLOGI to the group of devices for ULPs
4871 4871 */
4872 4872 static void
4873 4873 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4874 4874 {
4875 4875 int offline;
4876 4876 int count;
4877 4877 int rval;
4878 4878 uint32_t listlen;
4879 4879 uint32_t done;
4880 4880 uint32_t d_id;
4881 4881 fc_remote_node_t *node;
4882 4882 fc_remote_port_t *pd;
4883 4883 fc_remote_port_t *tmp_pd;
4884 4884 fc_packet_t *ulp_pkt;
4885 4885 la_els_logi_t *els_data;
4886 4886 ls_code_t ls_code;
4887 4887
4888 4888 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4889 4889 port, job);
4890 4890
4891 4891 done = 0;
4892 4892 listlen = job->job_ulp_listlen;
4893 4893 job->job_counter = job->job_ulp_listlen;
4894 4894
4895 4895 mutex_enter(&port->fp_mutex);
4896 4896 offline = (port->fp_statec_busy ||
4897 4897 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4898 4898 mutex_exit(&port->fp_mutex);
4899 4899
4900 4900 for (count = 0; count < listlen; count++) {
4901 4901 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4902 4902 sizeof (la_els_logi_t));
4903 4903
4904 4904 ulp_pkt = job->job_ulp_pkts[count];
4905 4905 pd = ulp_pkt->pkt_pd;
4906 4906 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4907 4907
4908 4908 if (offline) {
4909 4909 done++;
4910 4910
4911 4911 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4912 4912 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4913 4913 ulp_pkt->pkt_pd = NULL;
4914 4914 ulp_pkt->pkt_comp(ulp_pkt);
4915 4915
4916 4916 job->job_ulp_pkts[count] = NULL;
4917 4917
4918 4918 fp_jobdone(job);
4919 4919 continue;
4920 4920 }
4921 4921
4922 4922 if (pd == NULL) {
4923 4923 pd = fctl_get_remote_port_by_did(port, d_id);
4924 4924 if (pd == NULL) {
4925 4925 /* reset later */
4926 4926 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4927 4927 continue;
4928 4928 }
4929 4929 mutex_enter(&pd->pd_mutex);
4930 4930 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4931 4931 mutex_exit(&pd->pd_mutex);
4932 4932 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4933 4933 done++;
4934 4934 ulp_pkt->pkt_comp(ulp_pkt);
4935 4935 job->job_ulp_pkts[count] = NULL;
4936 4936 fp_jobdone(job);
4937 4937 } else {
4938 4938 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4939 4939 mutex_exit(&pd->pd_mutex);
4940 4940 }
4941 4941 continue;
4942 4942 }
4943 4943
4944 4944 switch (ulp_pkt->pkt_state) {
4945 4945 case FC_PKT_ELS_IN_PROGRESS:
4946 4946 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4947 4947 /* FALLTHRU */
4948 4948 case FC_PKT_LOCAL_RJT:
4949 4949 done++;
4950 4950 ulp_pkt->pkt_comp(ulp_pkt);
4951 4951 job->job_ulp_pkts[count] = NULL;
4952 4952 fp_jobdone(job);
4953 4953 continue;
4954 4954 default:
4955 4955 break;
4956 4956 }
4957 4957
4958 4958 /*
4959 4959 * Validate the pd corresponding to the d_id passed
4960 4960 * by the ULPs
4961 4961 */
4962 4962 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4963 4963 if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4964 4964 done++;
4965 4965 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4966 4966 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4967 4967 ulp_pkt->pkt_pd = NULL;
4968 4968 ulp_pkt->pkt_comp(ulp_pkt);
4969 4969 job->job_ulp_pkts[count] = NULL;
4970 4970 fp_jobdone(job);
4971 4971 continue;
4972 4972 }
4973 4973
4974 4974 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4975 4975 "port=%p, pd=%p", port, pd);
4976 4976
4977 4977 mutex_enter(&pd->pd_mutex);
4978 4978
4979 4979 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4980 4980 done++;
4981 4981 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4982 4982
4983 4983 ls_code.ls_code = LA_ELS_ACC;
4984 4984 ls_code.mbz = 0;
4985 4985
4986 4986 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4987 4987 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4988 4988 sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4989 4989
4990 4990 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4991 4991 (uint8_t *)&pd->pd_csp,
4992 4992 (uint8_t *)&els_data->common_service,
4993 4993 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4994 4994
4995 4995 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4996 4996 (uint8_t *)&pd->pd_port_name,
4997 4997 (uint8_t *)&els_data->nport_ww_name,
4998 4998 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
4999 4999
5000 5000 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5001 5001 (uint8_t *)&pd->pd_clsp1,
5002 5002 (uint8_t *)&els_data->class_1,
5003 5003 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
5004 5004
5005 5005 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5006 5006 (uint8_t *)&pd->pd_clsp2,
5007 5007 (uint8_t *)&els_data->class_2,
5008 5008 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
5009 5009
5010 5010 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5011 5011 (uint8_t *)&pd->pd_clsp3,
5012 5012 (uint8_t *)&els_data->class_3,
5013 5013 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
5014 5014
5015 5015 node = pd->pd_remote_nodep;
5016 5016 pd->pd_login_count++;
5017 5017 pd->pd_flags = PD_IDLE;
5018 5018 ulp_pkt->pkt_pd = pd;
5019 5019 mutex_exit(&pd->pd_mutex);
5020 5020
5021 5021 mutex_enter(&node->fd_mutex);
5022 5022 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5023 5023 (uint8_t *)&node->fd_node_name,
5024 5024 (uint8_t *)(&els_data->node_ww_name),
5025 5025 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
5026 5026
5027 5027 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5028 5028 (uint8_t *)&node->fd_vv,
5029 5029 (uint8_t *)(&els_data->vendor_version),
5030 5030 sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
5031 5031
5032 5032 mutex_exit(&node->fd_mutex);
5033 5033 ulp_pkt->pkt_state = FC_PKT_SUCCESS;
5034 5034 } else {
5035 5035
5036 5036 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
5037 5037 mutex_exit(&pd->pd_mutex);
5038 5038 }
5039 5039
5040 5040 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
5041 5041 ulp_pkt->pkt_comp(ulp_pkt);
5042 5042 job->job_ulp_pkts[count] = NULL;
5043 5043 fp_jobdone(job);
5044 5044 }
5045 5045 }
5046 5046
5047 5047 if (done == listlen) {
5048 5048 fp_jobwait(job);
5049 5049 fctl_jobdone(job);
5050 5050 return;
5051 5051 }
5052 5052
5053 5053 job->job_counter = listlen - done;
5054 5054
5055 5055 for (count = 0; count < listlen; count++) {
5056 5056 int cmd_flags;
5057 5057
5058 5058 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
5059 5059 continue;
5060 5060 }
5061 5061
5062 5062 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
5063 5063
5064 5064 cmd_flags = FP_CMD_PLOGI_RETAIN;
5065 5065
5066 5066 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5067 5067 ASSERT(d_id != 0);
5068 5068
5069 5069 pd = fctl_get_remote_port_by_did(port, d_id);
5070 5070
5071 5071 /*
5072 5072 * We need to properly adjust the port device
5073 5073 * reference counter before we assign the pd
5074 5074 * to the ULP packets port device pointer.
5075 5075 */
5076 5076 if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
5077 5077 mutex_enter(&pd->pd_mutex);
5078 5078 pd->pd_ref_count++;
5079 5079 mutex_exit(&pd->pd_mutex);
5080 5080 FP_TRACE(FP_NHEAD1(3, 0),
5081 5081 "fp_plogi_group: DID = 0x%x using new pd %p \
5082 5082 old pd NULL\n", d_id, pd);
5083 5083 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
5084 5084 ulp_pkt->pkt_pd != pd) {
5085 5085 mutex_enter(&pd->pd_mutex);
5086 5086 pd->pd_ref_count++;
5087 5087 mutex_exit(&pd->pd_mutex);
5088 5088 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5089 5089 ulp_pkt->pkt_pd->pd_ref_count--;
5090 5090 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5091 5091 FP_TRACE(FP_NHEAD1(3, 0),
5092 5092 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
5093 5093 d_id, ulp_pkt->pkt_pd, pd);
5094 5094 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
5095 5095 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5096 5096 ulp_pkt->pkt_pd->pd_ref_count--;
5097 5097 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5098 5098 FP_TRACE(FP_NHEAD1(3, 0),
5099 5099 "fp_plogi_group: DID = 0x%x pd is NULL and \
5100 5100 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
5101 5101 }
5102 5102
5103 5103 ulp_pkt->pkt_pd = pd;
5104 5104
5105 5105 if (pd != NULL) {
5106 5106 mutex_enter(&pd->pd_mutex);
5107 5107 d_id = pd->pd_port_id.port_id;
5108 5108 pd->pd_flags = PD_ELS_IN_PROGRESS;
5109 5109 mutex_exit(&pd->pd_mutex);
5110 5110 } else {
5111 5111 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5112 5112 #ifdef DEBUG
5113 5113 pd = fctl_get_remote_port_by_did(port, d_id);
5114 5114 ASSERT(pd == NULL);
5115 5115 #endif
5116 5116 /*
5117 5117 * In the Fabric topology, use NS to create
5118 5118 * port device, and if that fails still try
5119 5119 * with PLOGI - which will make yet another
5120 5120 * attempt to create after successful PLOGI
5121 5121 */
5122 5122 mutex_enter(&port->fp_mutex);
5123 5123 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5124 5124 mutex_exit(&port->fp_mutex);
5125 5125 pd = fp_create_remote_port_by_ns(port,
5126 5126 d_id, KM_SLEEP);
5127 5127 if (pd) {
5128 5128 cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5129 5129
5130 5130 mutex_enter(&pd->pd_mutex);
5131 5131 pd->pd_flags = PD_ELS_IN_PROGRESS;
5132 5132 mutex_exit(&pd->pd_mutex);
5133 5133
5134 5134 FP_TRACE(FP_NHEAD1(3, 0),
5135 5135 "fp_plogi_group;"
5136 5136 " NS created PD port=%p, job=%p,"
5137 5137 " pd=%p", port, job, pd);
5138 5138 }
5139 5139 } else {
5140 5140 mutex_exit(&port->fp_mutex);
5141 5141 }
5142 5142 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5143 5143 FP_TRACE(FP_NHEAD1(3, 0),
5144 5144 "fp_plogi_group;"
5145 5145 "ulp_pkt's pd is NULL, get a pd %p",
5146 5146 pd);
5147 5147 mutex_enter(&pd->pd_mutex);
5148 5148 pd->pd_ref_count++;
5149 5149 mutex_exit(&pd->pd_mutex);
5150 5150 }
5151 5151 ulp_pkt->pkt_pd = pd;
5152 5152 }
5153 5153
5154 5154 rval = fp_port_login(port, d_id, job, cmd_flags,
5155 5155 KM_SLEEP, pd, ulp_pkt);
5156 5156
5157 5157 if (rval == FC_SUCCESS) {
5158 5158 continue;
5159 5159 }
5160 5160
5161 5161 if (rval == FC_STATEC_BUSY) {
5162 5162 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5163 5163 ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5164 5164 } else {
5165 5165 ulp_pkt->pkt_state = FC_PKT_FAILURE;
5166 5166 }
5167 5167
5168 5168 if (pd) {
5169 5169 mutex_enter(&pd->pd_mutex);
5170 5170 pd->pd_flags = PD_IDLE;
5171 5171 mutex_exit(&pd->pd_mutex);
5172 5172 }
5173 5173
5174 5174 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5175 5175 ASSERT(pd != NULL);
5176 5176
5177 5177 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5178 5178 " PD removed; port=%p, job=%p", port, job);
5179 5179
5180 5180 mutex_enter(&pd->pd_mutex);
5181 5181 pd->pd_ref_count--;
5182 5182 node = pd->pd_remote_nodep;
5183 5183 mutex_exit(&pd->pd_mutex);
5184 5184
5185 5185 ASSERT(node != NULL);
5186 5186
5187 5187 if (fctl_destroy_remote_port(port, pd) == 0) {
5188 5188 fctl_destroy_remote_node(node);
5189 5189 }
5190 5190 ulp_pkt->pkt_pd = NULL;
5191 5191 }
5192 5192 ulp_pkt->pkt_comp(ulp_pkt);
5193 5193 fp_jobdone(job);
5194 5194 }
5195 5195
5196 5196 fp_jobwait(job);
5197 5197 fctl_jobdone(job);
5198 5198
5199 5199 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5200 5200 port, job);
5201 5201 }
5202 5202
5203 5203
5204 5204 /*
5205 5205 * Name server request initialization
5206 5206 */
5207 5207 static void
5208 5208 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5209 5209 {
5210 5210 int rval;
5211 5211 int count;
5212 5212 int size;
5213 5213
5214 5214 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5215 5215
5216 5216 job->job_counter = 1;
5217 5217 job->job_result = FC_SUCCESS;
5218 5218
5219 5219 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5220 5220 KM_SLEEP, NULL, NULL);
5221 5221
5222 5222 if (rval != FC_SUCCESS) {
5223 5223 mutex_enter(&port->fp_mutex);
5224 5224 port->fp_topology = FC_TOP_NO_NS;
5225 5225 mutex_exit(&port->fp_mutex);
5226 5226 return;
5227 5227 }
5228 5228
5229 5229 fp_jobwait(job);
5230 5230
5231 5231 if (job->job_result != FC_SUCCESS) {
5232 5232 mutex_enter(&port->fp_mutex);
5233 5233 port->fp_topology = FC_TOP_NO_NS;
5234 5234 mutex_exit(&port->fp_mutex);
5235 5235 return;
5236 5236 }
5237 5237
5238 5238 /*
5239 5239 * At this time, we'll do NS registration for objects in the
5240 5240 * ns_reg_cmds (see top of this file) array.
5241 5241 *
5242 5242 * Each time a ULP module registers with the transport, the
5243 5243 * appropriate fc4 bit is set fc4 types and registered with
5244 5244 * the NS for this support. Also, ULPs and FC admin utilities
5245 5245 * may do registration for objects like IP address, symbolic
5246 5246 * port/node name, Initial process associator at run time.
5247 5247 */
5248 5248 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5249 5249 job->job_counter = size;
5250 5250 job->job_result = FC_SUCCESS;
5251 5251
5252 5252 for (count = 0; count < size; count++) {
5253 5253 if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5254 5254 job, 0, sleep) != FC_SUCCESS) {
5255 5255 fp_jobdone(job);
5256 5256 }
5257 5257 }
5258 5258 if (size) {
5259 5259 fp_jobwait(job);
5260 5260 }
5261 5261
5262 5262 job->job_result = FC_SUCCESS;
5263 5263
5264 5264 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5265 5265
5266 5266 if (port->fp_dev_count < FP_MAX_DEVICES) {
5267 5267 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5268 5268 }
5269 5269
5270 5270 job->job_counter = 1;
5271 5271
5272 5272 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5273 5273 sleep) == FC_SUCCESS) {
5274 5274 fp_jobwait(job);
5275 5275 }
5276 5276 }
5277 5277
5278 5278
5279 5279 /*
5280 5280 * Name server finish:
5281 5281 * Unregister for RSCNs
5282 5282 * Unregister all the host port objects in the Name Server
5283 5283 * Perform LOGO with the NS;
5284 5284 */
5285 5285 static void
5286 5286 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5287 5287 {
5288 5288 fp_cmd_t *cmd;
5289 5289 uchar_t class;
5290 5290 uint32_t s_id;
5291 5291 fc_packet_t *pkt;
5292 5292 la_els_logo_t payload;
5293 5293
5294 5294 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5295 5295
5296 5296 job->job_counter = 1;
5297 5297
5298 5298 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5299 5299 FC_SUCCESS) {
5300 5300 fp_jobdone(job);
5301 5301 }
5302 5302 fp_jobwait(job);
5303 5303
5304 5304 job->job_counter = 1;
5305 5305
5306 5306 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5307 5307 fp_jobdone(job);
5308 5308 }
5309 5309 fp_jobwait(job);
5310 5310
5311 5311 job->job_counter = 1;
5312 5312
5313 5313 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5314 5314 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5315 5315 pkt = &cmd->cmd_pkt;
5316 5316
5317 5317 mutex_enter(&port->fp_mutex);
5318 5318 class = port->fp_ns_login_class;
5319 5319 s_id = port->fp_port_id.port_id;
5320 5320 payload.nport_id = port->fp_port_id;
5321 5321 mutex_exit(&port->fp_mutex);
5322 5322
5323 5323 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5324 5324 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5325 5325 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5326 5326 cmd->cmd_retry_count = 1;
5327 5327 cmd->cmd_ulp_pkt = NULL;
5328 5328
5329 5329 if (port->fp_npiv_type == FC_NPIV_PORT) {
5330 5330 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5331 5331 } else {
5332 5332 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5333 5333 }
5334 5334
5335 5335 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5336 5336
5337 5337 payload.ls_code.ls_code = LA_ELS_LOGO;
5338 5338 payload.ls_code.mbz = 0;
5339 5339 payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5340 5340
5341 5341 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
5342 5342 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5343 5343
5344 5344 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5345 5345 fp_iodone(cmd);
5346 5346 }
5347 5347 fp_jobwait(job);
5348 5348 }
5349 5349
5350 5350
5351 5351 /*
5352 5352 * NS Registration function.
5353 5353 *
5354 5354 * It should be seriously noted that FC-GS-2 currently doesn't support
5355 5355 * an Object Registration by a D_ID other than the owner of the object.
5356 5356 * What we are aiming at currently is to at least allow Symbolic Node/Port
5357 5357 * Name registration for any N_Port Identifier by the host software.
5358 5358 *
5359 5359 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5360 5360 * function treats the request as Host NS Object.
5361 5361 */
5362 5362 static int
5363 5363 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5364 5364 job_request_t *job, int polled, int sleep)
5365 5365 {
5366 5366 int rval;
5367 5367 fc_portid_t s_id;
5368 5368 fc_packet_t *pkt;
5369 5369 fp_cmd_t *cmd;
5370 5370
5371 5371 if (pd == NULL) {
5372 5372 mutex_enter(&port->fp_mutex);
5373 5373 s_id = port->fp_port_id;
5374 5374 mutex_exit(&port->fp_mutex);
5375 5375 } else {
5376 5376 mutex_enter(&pd->pd_mutex);
5377 5377 s_id = pd->pd_port_id;
5378 5378 mutex_exit(&pd->pd_mutex);
5379 5379 }
5380 5380
5381 5381 if (polled) {
5382 5382 job->job_counter = 1;
5383 5383 }
5384 5384
5385 5385 switch (cmd_code) {
5386 5386 case NS_RPN_ID:
5387 5387 case NS_RNN_ID: {
5388 5388 ns_rxn_req_t rxn;
5389 5389
5390 5390 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5391 5391 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5392 5392 if (cmd == NULL) {
5393 5393 return (FC_NOMEM);
5394 5394 }
5395 5395 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5396 5396 pkt = &cmd->cmd_pkt;
5397 5397
5398 5398 if (pd == NULL) {
5399 5399 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
5400 5400 (port->fp_service_params.nport_ww_name) :
5401 5401 (port->fp_service_params.node_ww_name));
5402 5402 } else {
5403 5403 if (cmd_code == NS_RPN_ID) {
5404 5404 mutex_enter(&pd->pd_mutex);
5405 5405 rxn.rxn_xname = pd->pd_port_name;
5406 5406 mutex_exit(&pd->pd_mutex);
5407 5407 } else {
5408 5408 fc_remote_node_t *node;
5409 5409
5410 5410 mutex_enter(&pd->pd_mutex);
5411 5411 node = pd->pd_remote_nodep;
5412 5412 mutex_exit(&pd->pd_mutex);
5413 5413
5414 5414 mutex_enter(&node->fd_mutex);
5415 5415 rxn.rxn_xname = node->fd_node_name;
5416 5416 mutex_exit(&node->fd_mutex);
5417 5417 }
5418 5418 }
5419 5419 rxn.rxn_port_id = s_id;
5420 5420
5421 5421 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5422 5422 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5423 5423 sizeof (rxn), DDI_DEV_AUTOINCR);
5424 5424
5425 5425 break;
5426 5426 }
5427 5427
5428 5428 case NS_RCS_ID: {
5429 5429 ns_rcos_t rcos;
5430 5430
5431 5431 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5432 5432 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5433 5433 if (cmd == NULL) {
5434 5434 return (FC_NOMEM);
5435 5435 }
5436 5436 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5437 5437 pkt = &cmd->cmd_pkt;
5438 5438
5439 5439 if (pd == NULL) {
5440 5440 rcos.rcos_cos = port->fp_cos;
5441 5441 } else {
5442 5442 mutex_enter(&pd->pd_mutex);
5443 5443 rcos.rcos_cos = pd->pd_cos;
5444 5444 mutex_exit(&pd->pd_mutex);
5445 5445 }
5446 5446 rcos.rcos_port_id = s_id;
5447 5447
5448 5448 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5449 5449 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5450 5450 sizeof (rcos), DDI_DEV_AUTOINCR);
5451 5451
5452 5452 break;
5453 5453 }
5454 5454
5455 5455 case NS_RFT_ID: {
5456 5456 ns_rfc_type_t rfc;
5457 5457
5458 5458 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5459 5459 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5460 5460 NULL);
5461 5461 if (cmd == NULL) {
5462 5462 return (FC_NOMEM);
5463 5463 }
5464 5464 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5465 5465 pkt = &cmd->cmd_pkt;
5466 5466
5467 5467 if (pd == NULL) {
5468 5468 mutex_enter(&port->fp_mutex);
5469 5469 bcopy(port->fp_fc4_types, rfc.rfc_types,
5470 5470 sizeof (port->fp_fc4_types));
5471 5471 mutex_exit(&port->fp_mutex);
5472 5472 } else {
5473 5473 mutex_enter(&pd->pd_mutex);
5474 5474 bcopy(pd->pd_fc4types, rfc.rfc_types,
5475 5475 sizeof (pd->pd_fc4types));
5476 5476 mutex_exit(&pd->pd_mutex);
5477 5477 }
5478 5478 rfc.rfc_port_id = s_id;
5479 5479
5480 5480 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5481 5481 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5482 5482 sizeof (rfc), DDI_DEV_AUTOINCR);
5483 5483
5484 5484 break;
5485 5485 }
5486 5486
5487 5487 case NS_RSPN_ID: {
5488 5488 uchar_t name_len;
5489 5489 int pl_size;
5490 5490 fc_portid_t spn;
5491 5491
5492 5492 if (pd == NULL) {
5493 5493 mutex_enter(&port->fp_mutex);
5494 5494 name_len = port->fp_sym_port_namelen;
5495 5495 mutex_exit(&port->fp_mutex);
5496 5496 } else {
5497 5497 mutex_enter(&pd->pd_mutex);
5498 5498 name_len = pd->pd_spn_len;
5499 5499 mutex_exit(&pd->pd_mutex);
5500 5500 }
5501 5501
5502 5502 pl_size = sizeof (fc_portid_t) + name_len + 1;
5503 5503
5504 5504 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5505 5505 sizeof (fc_reg_resp_t), sleep, NULL);
5506 5506 if (cmd == NULL) {
5507 5507 return (FC_NOMEM);
5508 5508 }
5509 5509
5510 5510 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5511 5511
5512 5512 pkt = &cmd->cmd_pkt;
5513 5513
5514 5514 spn = s_id;
5515 5515
5516 5516 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5517 5517 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5518 5518 DDI_DEV_AUTOINCR);
5519 5519 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5520 5520 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5521 5521 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5522 5522
5523 5523 if (pd == NULL) {
5524 5524 mutex_enter(&port->fp_mutex);
5525 5525 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5526 5526 (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5527 5527 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5528 5528 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5529 5529 mutex_exit(&port->fp_mutex);
5530 5530 } else {
5531 5531 mutex_enter(&pd->pd_mutex);
5532 5532 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5533 5533 (uint8_t *)pd->pd_spn,
5534 5534 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5535 5535 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5536 5536 mutex_exit(&pd->pd_mutex);
5537 5537 }
5538 5538 break;
5539 5539 }
5540 5540
5541 5541 case NS_RPT_ID: {
5542 5542 ns_rpt_t rpt;
5543 5543
5544 5544 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5545 5545 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5546 5546 if (cmd == NULL) {
5547 5547 return (FC_NOMEM);
5548 5548 }
5549 5549 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5550 5550 pkt = &cmd->cmd_pkt;
5551 5551
5552 5552 if (pd == NULL) {
5553 5553 rpt.rpt_type = port->fp_port_type;
5554 5554 } else {
5555 5555 mutex_enter(&pd->pd_mutex);
5556 5556 rpt.rpt_type = pd->pd_porttype;
5557 5557 mutex_exit(&pd->pd_mutex);
5558 5558 }
5559 5559 rpt.rpt_port_id = s_id;
5560 5560
5561 5561 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5562 5562 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5563 5563 sizeof (rpt), DDI_DEV_AUTOINCR);
5564 5564
5565 5565 break;
5566 5566 }
5567 5567
5568 5568 case NS_RIP_NN: {
5569 5569 ns_rip_t rip;
5570 5570
5571 5571 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5572 5572 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5573 5573 if (cmd == NULL) {
5574 5574 return (FC_NOMEM);
5575 5575 }
5576 5576 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5577 5577 pkt = &cmd->cmd_pkt;
5578 5578
5579 5579 if (pd == NULL) {
5580 5580 rip.rip_node_name =
5581 5581 port->fp_service_params.node_ww_name;
5582 5582 bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5583 5583 sizeof (port->fp_ip_addr));
5584 5584 } else {
5585 5585 fc_remote_node_t *node;
5586 5586
5587 5587 /*
5588 5588 * The most correct implementation should have the IP
5589 5589 * address in the fc_remote_node_t structure; I believe
5590 5590 * Node WWN and IP address should have one to one
5591 5591 * correlation (but guess what this is changing in
5592 5592 * FC-GS-2 latest draft)
5593 5593 */
5594 5594 mutex_enter(&pd->pd_mutex);
5595 5595 node = pd->pd_remote_nodep;
5596 5596 bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5597 5597 sizeof (pd->pd_ip_addr));
5598 5598 mutex_exit(&pd->pd_mutex);
5599 5599
5600 5600 mutex_enter(&node->fd_mutex);
5601 5601 rip.rip_node_name = node->fd_node_name;
5602 5602 mutex_exit(&node->fd_mutex);
5603 5603 }
5604 5604
5605 5605 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
5606 5606 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5607 5607 sizeof (rip), DDI_DEV_AUTOINCR);
5608 5608
5609 5609 break;
5610 5610 }
5611 5611
5612 5612 case NS_RIPA_NN: {
5613 5613 ns_ipa_t ipa;
5614 5614
5615 5615 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5616 5616 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5617 5617 if (cmd == NULL) {
5618 5618 return (FC_NOMEM);
5619 5619 }
5620 5620 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5621 5621 pkt = &cmd->cmd_pkt;
5622 5622
5623 5623 if (pd == NULL) {
5624 5624 ipa.ipa_node_name =
5625 5625 port->fp_service_params.node_ww_name;
5626 5626 bcopy(port->fp_ipa, ipa.ipa_value,
5627 5627 sizeof (port->fp_ipa));
5628 5628 } else {
5629 5629 fc_remote_node_t *node;
5630 5630
5631 5631 mutex_enter(&pd->pd_mutex);
5632 5632 node = pd->pd_remote_nodep;
5633 5633 mutex_exit(&pd->pd_mutex);
5634 5634
5635 5635 mutex_enter(&node->fd_mutex);
5636 5636 ipa.ipa_node_name = node->fd_node_name;
5637 5637 bcopy(node->fd_ipa, ipa.ipa_value,
5638 5638 sizeof (node->fd_ipa));
5639 5639 mutex_exit(&node->fd_mutex);
5640 5640 }
5641 5641
5642 5642 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5643 5643 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5644 5644 sizeof (ipa), DDI_DEV_AUTOINCR);
5645 5645
5646 5646 break;
5647 5647 }
5648 5648
5649 5649 case NS_RSNN_NN: {
5650 5650 uchar_t name_len;
5651 5651 int pl_size;
5652 5652 la_wwn_t snn;
5653 5653 fc_remote_node_t *node = NULL;
5654 5654
5655 5655 if (pd == NULL) {
5656 5656 mutex_enter(&port->fp_mutex);
5657 5657 name_len = port->fp_sym_node_namelen;
5658 5658 mutex_exit(&port->fp_mutex);
5659 5659 } else {
5660 5660 mutex_enter(&pd->pd_mutex);
5661 5661 node = pd->pd_remote_nodep;
5662 5662 mutex_exit(&pd->pd_mutex);
5663 5663
5664 5664 mutex_enter(&node->fd_mutex);
5665 5665 name_len = node->fd_snn_len;
5666 5666 mutex_exit(&node->fd_mutex);
5667 5667 }
5668 5668
5669 5669 pl_size = sizeof (la_wwn_t) + name_len + 1;
5670 5670
5671 5671 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5672 5672 pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5673 5673 if (cmd == NULL) {
5674 5674 return (FC_NOMEM);
5675 5675 }
5676 5676 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5677 5677
5678 5678 pkt = &cmd->cmd_pkt;
5679 5679
5680 5680 bcopy(&port->fp_service_params.node_ww_name,
5681 5681 &snn, sizeof (la_wwn_t));
5682 5682
5683 5683 if (pd == NULL) {
5684 5684 mutex_enter(&port->fp_mutex);
5685 5685 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5686 5686 (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5687 5687 (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5688 5688 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5689 5689 mutex_exit(&port->fp_mutex);
5690 5690 } else {
5691 5691 ASSERT(node != NULL);
5692 5692 mutex_enter(&node->fd_mutex);
5693 5693 FC_SET_CMD(port, pkt->pkt_cmd_acc,
5694 5694 (uint8_t *)node->fd_snn,
5695 5695 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5696 5696 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5697 5697 mutex_exit(&node->fd_mutex);
5698 5698 }
5699 5699
5700 5700 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
5701 5701 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5702 5702 sizeof (snn), DDI_DEV_AUTOINCR);
5703 5703 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5704 5704 (uint8_t *)(pkt->pkt_cmd
5705 5705 + sizeof (fc_ct_header_t) + sizeof (snn)),
5706 5706 1, DDI_DEV_AUTOINCR);
5707 5707
5708 5708 break;
5709 5709 }
5710 5710
5711 5711 case NS_DA_ID: {
5712 5712 ns_remall_t rall;
5713 5713 char tmp[4] = {0};
5714 5714 char *ptr;
5715 5715
5716 5716 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5717 5717 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5718 5718
5719 5719 if (cmd == NULL) {
5720 5720 return (FC_NOMEM);
5721 5721 }
5722 5722
5723 5723 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5724 5724 pkt = &cmd->cmd_pkt;
5725 5725
5726 5726 ptr = (char *)(&s_id);
5727 5727 tmp[3] = *ptr++;
5728 5728 tmp[2] = *ptr++;
5729 5729 tmp[1] = *ptr++;
5730 5730 tmp[0] = *ptr;
5731 5731 #if defined(_BIT_FIELDS_LTOH)
5732 5732 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5733 5733 #else
5734 5734 rall.rem_port_id = s_id;
5735 5735 #endif
5736 5736 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
5737 5737 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5738 5738 sizeof (rall), DDI_DEV_AUTOINCR);
5739 5739
5740 5740 break;
5741 5741 }
5742 5742
5743 5743 default:
5744 5744 return (FC_FAILURE);
5745 5745 }
5746 5746
5747 5747 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5748 5748
5749 5749 if (rval != FC_SUCCESS) {
5750 5750 job->job_result = rval;
5751 5751 fp_iodone(cmd);
5752 5752 }
5753 5753
5754 5754 if (polled) {
5755 5755 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5756 5756 fp_jobwait(job);
5757 5757 } else {
5758 5758 rval = FC_SUCCESS;
5759 5759 }
5760 5760
5761 5761 return (rval);
5762 5762 }
5763 5763
5764 5764
5765 5765 /*
5766 5766 * Common interrupt handler
5767 5767 */
5768 5768 static int
5769 5769 fp_common_intr(fc_packet_t *pkt, int iodone)
5770 5770 {
5771 5771 int rval = FC_FAILURE;
5772 5772 fp_cmd_t *cmd;
5773 5773 fc_local_port_t *port;
5774 5774
5775 5775 cmd = pkt->pkt_ulp_private;
5776 5776 port = cmd->cmd_port;
5777 5777
5778 5778 /*
5779 5779 * Fail fast the upper layer requests if
5780 5780 * a state change has occurred amidst.
5781 5781 */
5782 5782 mutex_enter(&port->fp_mutex);
5783 5783 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5784 5784 mutex_exit(&port->fp_mutex);
5785 5785 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5786 5786 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5787 5787 } else if (!(port->fp_soft_state &
5788 5788 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5789 5789 mutex_exit(&port->fp_mutex);
5790 5790
5791 5791 switch (pkt->pkt_state) {
5792 5792 case FC_PKT_LOCAL_BSY:
5793 5793 case FC_PKT_FABRIC_BSY:
5794 5794 case FC_PKT_NPORT_BSY:
5795 5795 case FC_PKT_TIMEOUT:
5796 5796 cmd->cmd_retry_interval = (pkt->pkt_state ==
5797 5797 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5798 5798 rval = fp_retry_cmd(pkt);
5799 5799 break;
5800 5800
5801 5801 case FC_PKT_FABRIC_RJT:
5802 5802 case FC_PKT_NPORT_RJT:
5803 5803 case FC_PKT_LOCAL_RJT:
5804 5804 case FC_PKT_LS_RJT:
5805 5805 case FC_PKT_FS_RJT:
5806 5806 case FC_PKT_BA_RJT:
5807 5807 rval = fp_handle_reject(pkt);
5808 5808 break;
5809 5809
5810 5810 default:
5811 5811 if (pkt->pkt_resp_resid) {
5812 5812 cmd->cmd_retry_interval = 0;
5813 5813 rval = fp_retry_cmd(pkt);
5814 5814 }
5815 5815 break;
5816 5816 }
5817 5817 } else {
5818 5818 mutex_exit(&port->fp_mutex);
5819 5819 }
5820 5820
5821 5821 if (rval != FC_SUCCESS && iodone) {
5822 5822 fp_iodone(cmd);
5823 5823 rval = FC_SUCCESS;
5824 5824 }
5825 5825
5826 5826 return (rval);
5827 5827 }
5828 5828
5829 5829
5830 5830 /*
5831 5831 * Some not so long winding theory on point to point topology:
5832 5832 *
5833 5833 * In the ACC payload, if the D_ID is ZERO and the common service
5834 5834 * parameters indicate N_Port, then the topology is POINT TO POINT.
5835 5835 *
5836 5836 * In a point to point topology with an N_Port, during Fabric Login,
5837 5837 * the destination N_Port will check with our WWN and decide if it
5838 5838 * needs to issue PLOGI or not. That means, FLOGI could potentially
5839 5839 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5840 5840 * PLOGI creates the device handles.
5841 5841 *
5842 5842 * Assuming that the host port WWN is greater than the other N_Port
5843 5843 * WWN, then we become the master (be aware that this isn't the word
5844 5844 * used in the FC standards) and initiate the PLOGI.
5845 5845 *
5846 5846 */
5847 5847 static void
5848 5848 fp_flogi_intr(fc_packet_t *pkt)
5849 5849 {
5850 5850 int state;
5851 5851 int f_port;
5852 5852 uint32_t s_id;
5853 5853 uint32_t d_id;
5854 5854 fp_cmd_t *cmd;
5855 5855 fc_local_port_t *port;
5856 5856 la_wwn_t *swwn;
5857 5857 la_wwn_t dwwn;
5858 5858 la_wwn_t nwwn;
5859 5859 fc_remote_port_t *pd;
5860 5860 la_els_logi_t *acc;
5861 5861 com_svc_t csp;
5862 5862 ls_code_t resp;
5863 5863
5864 5864 cmd = pkt->pkt_ulp_private;
5865 5865 port = cmd->cmd_port;
5866 5866
5867 5867 mutex_enter(&port->fp_mutex);
5868 5868 port->fp_out_fpcmds--;
5869 5869 mutex_exit(&port->fp_mutex);
5870 5870
5871 5871 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5872 5872 port, pkt, pkt->pkt_state);
5873 5873
5874 5874 if (FP_IS_PKT_ERROR(pkt)) {
5875 5875 (void) fp_common_intr(pkt, 1);
5876 5876 return;
5877 5877 }
5878 5878
5879 5879 /*
5880 5880 * Currently, we don't need to swap bytes here because qlc is faking the
5881 5881 * response for us and so endianness is getting taken care of. But we
5882 5882 * have to fix this and generalize this at some point
5883 5883 */
5884 5884 acc = (la_els_logi_t *)pkt->pkt_resp;
5885 5885
5886 5886 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5887 5887 sizeof (resp), DDI_DEV_AUTOINCR);
5888 5888
5889 5889 ASSERT(resp.ls_code == LA_ELS_ACC);
5890 5890 if (resp.ls_code != LA_ELS_ACC) {
5891 5891 (void) fp_common_intr(pkt, 1);
5892 5892 return;
5893 5893 }
5894 5894
5895 5895 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
5896 5896 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5897 5897
5898 5898 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5899 5899
5900 5900 ASSERT(!MUTEX_HELD(&port->fp_mutex));
5901 5901
5902 5902 mutex_enter(&port->fp_mutex);
5903 5903 state = FC_PORT_STATE_MASK(port->fp_state);
5904 5904 mutex_exit(&port->fp_mutex);
5905 5905
5906 5906 if (f_port == 0) {
5907 5907 if (state != FC_STATE_LOOP) {
5908 5908 swwn = &port->fp_service_params.nport_ww_name;
5909 5909
5910 5910 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5911 5911 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5912 5912 DDI_DEV_AUTOINCR);
5913 5913
5914 5914 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5915 5915 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5916 5916 DDI_DEV_AUTOINCR);
5917 5917
5918 5918 mutex_enter(&port->fp_mutex);
5919 5919
5920 5920 port->fp_topology = FC_TOP_PT_PT;
5921 5921 port->fp_total_devices = 1;
5922 5922 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5923 5923 port->fp_ptpt_master = 1;
5924 5924 /*
5925 5925 * Let us choose 'X' as S_ID and 'Y'
5926 5926 * as D_ID and that'll work; hopefully
5927 5927 * If not, it will get changed.
5928 5928 */
5929 5929 s_id = port->fp_instance + FP_DEFAULT_SID;
5930 5930 d_id = port->fp_instance + FP_DEFAULT_DID;
5931 5931 port->fp_port_id.port_id = s_id;
5932 5932 mutex_exit(&port->fp_mutex);
5933 5933
5934 5934 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
5935 5935 "pd %x", port->fp_port_id.port_id, d_id);
5936 5936 pd = fctl_create_remote_port(port,
5937 5937 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5938 5938 KM_NOSLEEP);
5939 5939 if (pd == NULL) {
5940 5940 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5941 5941 0, NULL, "couldn't create device"
5942 5942 " d_id=%X", d_id);
5943 5943 fp_iodone(cmd);
5944 5944 return;
5945 5945 }
5946 5946
5947 5947 cmd->cmd_pkt.pkt_tran_flags =
5948 5948 pkt->pkt_tran_flags;
5949 5949 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5950 5950 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5951 5951 cmd->cmd_retry_count = fp_retry_count;
5952 5952
5953 5953 fp_xlogi_init(port, cmd, s_id, d_id,
5954 5954 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5955 5955
5956 5956 (&cmd->cmd_pkt)->pkt_pd = pd;
5957 5957
5958 5958 /*
5959 5959 * We've just created this fc_remote_port_t, and
5960 5960 * we're about to use it to send a PLOGI, so
5961 5961 * bump the reference count right now. When
5962 5962 * the packet is freed, the reference count will
5963 5963 * be decremented. The ULP may also start using
5964 5964 * it, so mark it as given away as well.
5965 5965 */
5966 5966 pd->pd_ref_count++;
5967 5967 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5968 5968
5969 5969 if (fp_sendcmd(port, cmd,
5970 5970 port->fp_fca_handle) == FC_SUCCESS) {
5971 5971 return;
5972 5972 }
5973 5973 } else {
5974 5974 /*
5975 5975 * The device handles will be created when the
5976 5976 * unsolicited PLOGI is completed successfully
5977 5977 */
5978 5978 port->fp_ptpt_master = 0;
5979 5979 mutex_exit(&port->fp_mutex);
5980 5980 }
5981 5981 }
5982 5982 pkt->pkt_state = FC_PKT_FAILURE;
5983 5983 } else {
5984 5984 if (f_port) {
5985 5985 mutex_enter(&port->fp_mutex);
5986 5986 if (state == FC_STATE_LOOP) {
5987 5987 port->fp_topology = FC_TOP_PUBLIC_LOOP;
5988 5988 } else {
5989 5989 port->fp_topology = FC_TOP_FABRIC;
5990 5990
5991 5991 FC_GET_RSP(port, pkt->pkt_resp_acc,
5992 5992 (uint8_t *)&port->fp_fabric_name,
5993 5993 (uint8_t *)&acc->node_ww_name,
5994 5994 sizeof (la_wwn_t),
5995 5995 DDI_DEV_AUTOINCR);
5996 5996 }
5997 5997 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5998 5998 mutex_exit(&port->fp_mutex);
5999 5999 } else {
6000 6000 pkt->pkt_state = FC_PKT_FAILURE;
6001 6001 }
6002 6002 }
6003 6003 fp_iodone(cmd);
6004 6004 }
6005 6005
6006 6006
6007 6007 /*
6008 6008 * Handle solicited PLOGI response
6009 6009 */
6010 6010 static void
6011 6011 fp_plogi_intr(fc_packet_t *pkt)
6012 6012 {
6013 6013 int nl_port;
6014 6014 int bailout;
6015 6015 uint32_t d_id;
6016 6016 fp_cmd_t *cmd;
6017 6017 la_els_logi_t *acc;
6018 6018 fc_local_port_t *port;
6019 6019 fc_remote_port_t *pd;
6020 6020 la_wwn_t nwwn;
6021 6021 la_wwn_t pwwn;
6022 6022 ls_code_t resp;
6023 6023
6024 6024 nl_port = 0;
6025 6025 cmd = pkt->pkt_ulp_private;
6026 6026 port = cmd->cmd_port;
6027 6027 d_id = pkt->pkt_cmd_fhdr.d_id;
6028 6028
6029 6029 #ifndef __lock_lint
6030 6030 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6031 6031 #endif
6032 6032
6033 6033 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
6034 6034 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
6035 6035 cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
6036 6036
6037 6037 /*
6038 6038 * Bail out early on ULP initiated requests if the
6039 6039 * state change has occurred
6040 6040 */
6041 6041 mutex_enter(&port->fp_mutex);
6042 6042 port->fp_out_fpcmds--;
6043 6043 bailout = ((port->fp_statec_busy ||
6044 6044 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6045 6045 cmd->cmd_ulp_pkt) ? 1 : 0;
6046 6046 mutex_exit(&port->fp_mutex);
6047 6047
6048 6048 if (FP_IS_PKT_ERROR(pkt) || bailout) {
6049 6049 int skip_msg = 0;
6050 6050 int giveup = 0;
6051 6051
6052 6052 if (cmd->cmd_ulp_pkt) {
6053 6053 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6054 6054 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
6055 6055 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6056 6056 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6057 6057 }
6058 6058
6059 6059 /*
6060 6060 * If an unsolicited cross login already created
6061 6061 * a device speed up the discovery by not retrying
6062 6062 * the command mindlessly.
6063 6063 */
6064 6064 if (pkt->pkt_pd == NULL &&
6065 6065 fctl_get_remote_port_by_did(port, d_id) != NULL) {
6066 6066 fp_iodone(cmd);
6067 6067 return;
6068 6068 }
6069 6069
6070 6070 if (pkt->pkt_pd != NULL) {
6071 6071 giveup = (pkt->pkt_pd->pd_recepient ==
6072 6072 PD_PLOGI_RECEPIENT) ? 1 : 0;
6073 6073 if (giveup) {
6074 6074 /*
6075 6075 * This pd is marked as plogi
6076 6076 * recipient, stop retrying
6077 6077 */
6078 6078 FP_TRACE(FP_NHEAD1(3, 0),
6079 6079 "fp_plogi_intr: stop retry as"
6080 6080 " a cross login was accepted"
6081 6081 " from d_id=%x, port=%p.",
6082 6082 d_id, port);
6083 6083 fp_iodone(cmd);
6084 6084 return;
6085 6085 }
6086 6086 }
6087 6087
6088 6088 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6089 6089 return;
6090 6090 }
6091 6091
6092 6092 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
6093 6093 mutex_enter(&pd->pd_mutex);
6094 6094 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
6095 6095 skip_msg++;
6096 6096 }
6097 6097 mutex_exit(&pd->pd_mutex);
6098 6098 }
6099 6099
6100 6100 mutex_enter(&port->fp_mutex);
6101 6101 if (!bailout && !(skip_msg && port->fp_statec_busy) &&
6102 6102 port->fp_statec_busy <= 1 &&
6103 6103 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
6104 6104 mutex_exit(&port->fp_mutex);
6105 6105 /*
6106 6106 * In case of Login Collisions, JNI HBAs returns the
6107 6107 * FC pkt back to the Initiator with the state set to
6108 6108 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
6109 6109 * QLC HBAs handles such cases in the FW and doesnot
6110 6110 * return the LS_RJT with Logical error when
6111 6111 * login collision happens.
6112 6112 */
6113 6113 if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6114 6114 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6115 6115 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6116 6116 "PLOGI to %x failed", d_id);
6117 6117 }
6118 6118 FP_TRACE(FP_NHEAD2(9, 0),
6119 6119 "PLOGI to %x failed. state=%x reason=%x.",
6120 6120 d_id, pkt->pkt_state, pkt->pkt_reason);
6121 6121 } else {
6122 6122 mutex_exit(&port->fp_mutex);
6123 6123 }
6124 6124
6125 6125 fp_iodone(cmd);
6126 6126 return;
6127 6127 }
6128 6128
6129 6129 acc = (la_els_logi_t *)pkt->pkt_resp;
6130 6130
6131 6131 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6132 6132 sizeof (resp), DDI_DEV_AUTOINCR);
6133 6133
6134 6134 ASSERT(resp.ls_code == LA_ELS_ACC);
6135 6135 if (resp.ls_code != LA_ELS_ACC) {
6136 6136 (void) fp_common_intr(pkt, 1);
6137 6137 return;
6138 6138 }
6139 6139
6140 6140 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6141 6141 mutex_enter(&port->fp_mutex);
6142 6142 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6143 6143 mutex_exit(&port->fp_mutex);
6144 6144 fp_iodone(cmd);
6145 6145 return;
6146 6146 }
6147 6147
6148 6148 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6149 6149
6150 6150 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6151 6151 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6152 6152 DDI_DEV_AUTOINCR);
6153 6153
6154 6154 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6155 6155 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6156 6156 DDI_DEV_AUTOINCR);
6157 6157
6158 6158 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6159 6159 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6160 6160
6161 6161 if ((pd = pkt->pkt_pd) == NULL) {
6162 6162 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6163 6163 if (pd == NULL) {
6164 6164 FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x",
6165 6165 port->fp_port_id.port_id, d_id);
6166 6166 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6167 6167 PD_PLOGI_INITIATOR, KM_NOSLEEP);
6168 6168 if (pd == NULL) {
6169 6169 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6170 6170 "couldn't create port device handles"
6171 6171 " d_id=%x", d_id);
6172 6172 fp_iodone(cmd);
6173 6173 return;
6174 6174 }
6175 6175 } else {
6176 6176 fc_remote_port_t *tmp_pd;
6177 6177
6178 6178 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6179 6179 if (tmp_pd != NULL) {
6180 6180 fp_iodone(cmd);
6181 6181 return;
6182 6182 }
6183 6183
6184 6184 mutex_enter(&port->fp_mutex);
6185 6185 mutex_enter(&pd->pd_mutex);
6186 6186 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6187 6187 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6188 6188 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6189 6189 }
6190 6190
6191 6191 if (pd->pd_type == PORT_DEVICE_OLD) {
6192 6192 if (pd->pd_port_id.port_id != d_id) {
6193 6193 fctl_delist_did_table(port, pd);
6194 6194 pd->pd_type = PORT_DEVICE_CHANGED;
6195 6195 pd->pd_port_id.port_id = d_id;
6196 6196 } else {
6197 6197 pd->pd_type = PORT_DEVICE_NOCHANGE;
6198 6198 }
6199 6199 }
6200 6200
6201 6201 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6202 6202 char ww_name[17];
6203 6203
6204 6204 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6205 6205
6206 6206 mutex_exit(&pd->pd_mutex);
6207 6207 mutex_exit(&port->fp_mutex);
6208 6208 FP_TRACE(FP_NHEAD2(9, 0),
6209 6209 "Possible Duplicate name or address"
6210 6210 " identifiers in the PLOGI response"
6211 6211 " D_ID=%x, PWWN=%s: Please check the"
6212 6212 " configuration", d_id, ww_name);
6213 6213 fp_iodone(cmd);
6214 6214 return;
6215 6215 }
6216 6216 fctl_enlist_did_table(port, pd);
6217 6217 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6218 6218 mutex_exit(&pd->pd_mutex);
6219 6219 mutex_exit(&port->fp_mutex);
6220 6220 }
6221 6221 } else {
6222 6222 fc_remote_port_t *tmp_pd, *new_wwn_pd;
6223 6223
6224 6224 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6225 6225 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6226 6226
6227 6227 mutex_enter(&port->fp_mutex);
6228 6228 mutex_enter(&pd->pd_mutex);
6229 6229 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6230 6230 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6231 6231 " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6232 6232 pd->pd_type);
6233 6233 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6234 6234 pd->pd_type == PORT_DEVICE_OLD) ||
6235 6235 (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6236 6236 pd->pd_type = PORT_DEVICE_NOCHANGE;
6237 6237 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6238 6238 pd->pd_type = PORT_DEVICE_NEW;
6239 6239 }
6240 6240 } else {
6241 6241 char old_name[17];
6242 6242 char new_name[17];
6243 6243
6244 6244 fc_wwn_to_str(&pd->pd_port_name, old_name);
6245 6245 fc_wwn_to_str(&pwwn, new_name);
6246 6246
6247 6247 FP_TRACE(FP_NHEAD1(9, 0),
6248 6248 "fp_plogi_intr: PWWN of a device with D_ID=%x "
6249 6249 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6250 6250 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6251 6251 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6252 6252 cmd->cmd_ulp_pkt, bailout);
6253 6253
6254 6254 FP_TRACE(FP_NHEAD2(9, 0),
6255 6255 "PWWN of a device with D_ID=%x changed."
6256 6256 " New PWWN = %s, OLD PWWN = %s", d_id,
6257 6257 new_name, old_name);
6258 6258
6259 6259 if (cmd->cmd_ulp_pkt && !bailout) {
6260 6260 fc_remote_node_t *rnodep;
6261 6261 fc_portmap_t *changelist;
6262 6262 fc_portmap_t *listptr;
6263 6263 int len = 1;
6264 6264 /* # entries in changelist */
6265 6265
6266 6266 fctl_delist_pwwn_table(port, pd);
6267 6267
6268 6268 /*
6269 6269 * Lets now check if there already is a pd with
6270 6270 * this new WWN in the table. If so, we'll mark
6271 6271 * it as invalid
6272 6272 */
6273 6273
6274 6274 if (new_wwn_pd) {
6275 6275 /*
6276 6276 * There is another pd with in the pwwn
6277 6277 * table with the same WWN that we got
6278 6278 * in the PLOGI payload. We have to get
6279 6279 * it out of the pwwn table, update the
6280 6280 * pd's state (fp_fillout_old_map does
6281 6281 * this for us) and add it to the
6282 6282 * changelist that goes up to ULPs.
6283 6283 *
6284 6284 * len is length of changelist and so
6285 6285 * increment it.
6286 6286 */
6287 6287 len++;
6288 6288
6289 6289 if (tmp_pd != pd) {
6290 6290 /*
6291 6291 * Odd case where pwwn and did
6292 6292 * tables are out of sync but
6293 6293 * we will handle that too. See
6294 6294 * more comments below.
6295 6295 *
6296 6296 * One more device that ULPs
6297 6297 * should know about and so len
6298 6298 * gets incremented again.
6299 6299 */
6300 6300 len++;
6301 6301 }
6302 6302
6303 6303 listptr = changelist = kmem_zalloc(len *
6304 6304 sizeof (*changelist), KM_SLEEP);
6305 6305
6306 6306 mutex_enter(&new_wwn_pd->pd_mutex);
6307 6307 rnodep = new_wwn_pd->pd_remote_nodep;
6308 6308 mutex_exit(&new_wwn_pd->pd_mutex);
6309 6309
6310 6310 /*
6311 6311 * Hold the fd_mutex since
6312 6312 * fctl_copy_portmap_held expects it.
6313 6313 * Preserve lock hierarchy by grabbing
6314 6314 * fd_mutex before pd_mutex
6315 6315 */
6316 6316 if (rnodep) {
6317 6317 mutex_enter(&rnodep->fd_mutex);
6318 6318 }
6319 6319 mutex_enter(&new_wwn_pd->pd_mutex);
6320 6320 fp_fillout_old_map_held(listptr++,
6321 6321 new_wwn_pd, 0);
6322 6322 mutex_exit(&new_wwn_pd->pd_mutex);
6323 6323 if (rnodep) {
6324 6324 mutex_exit(&rnodep->fd_mutex);
6325 6325 }
6326 6326
6327 6327 /*
6328 6328 * Safety check :
6329 6329 * Lets ensure that the pwwn and did
6330 6330 * tables are in sync. Ideally, we
6331 6331 * should not find that these two pd's
6332 6332 * are different.
6333 6333 */
6334 6334 if (tmp_pd != pd) {
6335 6335 mutex_enter(&tmp_pd->pd_mutex);
6336 6336 rnodep =
6337 6337 tmp_pd->pd_remote_nodep;
6338 6338 mutex_exit(&tmp_pd->pd_mutex);
6339 6339
6340 6340 /* As above grab fd_mutex */
6341 6341 if (rnodep) {
6342 6342 mutex_enter(&rnodep->
6343 6343 fd_mutex);
6344 6344 }
6345 6345 mutex_enter(&tmp_pd->pd_mutex);
6346 6346
6347 6347 fp_fillout_old_map_held(
6348 6348 listptr++, tmp_pd, 0);
6349 6349
6350 6350 mutex_exit(&tmp_pd->pd_mutex);
6351 6351 if (rnodep) {
6352 6352 mutex_exit(&rnodep->
6353 6353 fd_mutex);
6354 6354 }
6355 6355
6356 6356 /*
6357 6357 * Now add "pd" (not tmp_pd)
6358 6358 * to fp_did_table to sync it up
6359 6359 * with fp_pwwn_table
6360 6360 *
6361 6361 * pd->pd_mutex is already held
6362 6362 * at this point
6363 6363 */
6364 6364 fctl_enlist_did_table(port, pd);
6365 6365 }
6366 6366 } else {
6367 6367 listptr = changelist = kmem_zalloc(
6368 6368 sizeof (*changelist), KM_SLEEP);
6369 6369 }
6370 6370
6371 6371 ASSERT(changelist != NULL);
6372 6372
6373 6373 fp_fillout_changed_map(listptr, pd, &d_id,
6374 6374 &pwwn);
6375 6375 fctl_enlist_pwwn_table(port, pd);
6376 6376
6377 6377 mutex_exit(&pd->pd_mutex);
6378 6378 mutex_exit(&port->fp_mutex);
6379 6379
6380 6380 fp_iodone(cmd);
6381 6381
6382 6382 (void) fp_ulp_devc_cb(port, changelist, len,
6383 6383 len, KM_NOSLEEP, 0);
6384 6384
6385 6385 return;
6386 6386 }
6387 6387 }
6388 6388
6389 6389 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6390 6390 nl_port = 1;
6391 6391 }
6392 6392 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6393 6393 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6394 6394 }
6395 6395
6396 6396 mutex_exit(&pd->pd_mutex);
6397 6397 mutex_exit(&port->fp_mutex);
6398 6398
6399 6399 if (tmp_pd == NULL) {
6400 6400 mutex_enter(&port->fp_mutex);
6401 6401 mutex_enter(&pd->pd_mutex);
6402 6402 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6403 6403 char ww_name[17];
6404 6404
6405 6405 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6406 6406 mutex_exit(&pd->pd_mutex);
6407 6407 mutex_exit(&port->fp_mutex);
6408 6408 FP_TRACE(FP_NHEAD2(9, 0),
6409 6409 "Possible Duplicate name or address"
6410 6410 " identifiers in the PLOGI response"
6411 6411 " D_ID=%x, PWWN=%s: Please check the"
6412 6412 " configuration", d_id, ww_name);
6413 6413 fp_iodone(cmd);
6414 6414 return;
6415 6415 }
6416 6416 fctl_enlist_did_table(port, pd);
6417 6417 pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6418 6418 mutex_exit(&pd->pd_mutex);
6419 6419 mutex_exit(&port->fp_mutex);
6420 6420 }
6421 6421 }
6422 6422 fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6423 6423 FC_TRAN_CLASS(pkt->pkt_tran_flags));
6424 6424
6425 6425 if (cmd->cmd_ulp_pkt) {
6426 6426 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6427 6427 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6428 6428 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6429 6429 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6430 6430 if (pd != NULL) {
6431 6431 FP_TRACE(FP_NHEAD1(9, 0),
6432 6432 "fp_plogi_intr;"
6433 6433 "ulp_pkt's pd is NULL, get a pd %p",
6434 6434 pd);
6435 6435 mutex_enter(&pd->pd_mutex);
6436 6436 pd->pd_ref_count++;
6437 6437 mutex_exit(&pd->pd_mutex);
6438 6438 }
6439 6439 cmd->cmd_ulp_pkt->pkt_pd = pd;
6440 6440 }
6441 6441 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6442 6442 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6443 6443 sizeof (fc_frame_hdr_t));
6444 6444 bcopy((caddr_t)pkt->pkt_resp,
6445 6445 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6446 6446 sizeof (la_els_logi_t));
6447 6447 }
6448 6448
6449 6449 mutex_enter(&port->fp_mutex);
6450 6450 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6451 6451 mutex_enter(&pd->pd_mutex);
6452 6452
6453 6453 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6454 6454 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6455 6455 cmd->cmd_retry_count = fp_retry_count;
6456 6456
6457 6457 /*
6458 6458 * If the fc_remote_port_t pointer is not set in the given
6459 6459 * fc_packet_t, then this fc_remote_port_t must have just
6460 6460 * been created. Save the pointer and also increment the
6461 6461 * fc_remote_port_t reference count.
6462 6462 */
6463 6463 if (pkt->pkt_pd == NULL) {
6464 6464 pkt->pkt_pd = pd;
6465 6465 pd->pd_ref_count++; /* It's in use! */
6466 6466 }
6467 6467
6468 6468 fp_adisc_init(cmd, cmd->cmd_job);
6469 6469
6470 6470 pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6471 6471 pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6472 6472
6473 6473 mutex_exit(&pd->pd_mutex);
6474 6474 mutex_exit(&port->fp_mutex);
6475 6475
6476 6476 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6477 6477 return;
6478 6478 }
6479 6479 } else {
6480 6480 mutex_exit(&port->fp_mutex);
6481 6481 }
6482 6482
6483 6483 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6484 6484 mutex_enter(&port->fp_mutex);
6485 6485 mutex_enter(&pd->pd_mutex);
6486 6486
6487 6487 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6488 6488 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6489 6489 cmd->cmd_retry_count = fp_retry_count;
6490 6490
6491 6491 fp_logo_init(pd, cmd, cmd->cmd_job);
6492 6492
6493 6493 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6494 6494 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6495 6495
6496 6496 mutex_exit(&pd->pd_mutex);
6497 6497 mutex_exit(&port->fp_mutex);
6498 6498
6499 6499 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6500 6500 return;
6501 6501 }
6502 6502
6503 6503 }
6504 6504 fp_iodone(cmd);
6505 6505 }
6506 6506
6507 6507
6508 6508 /*
6509 6509 * Handle solicited ADISC response
6510 6510 */
6511 6511 static void
6512 6512 fp_adisc_intr(fc_packet_t *pkt)
6513 6513 {
6514 6514 int rval;
6515 6515 int bailout;
6516 6516 fp_cmd_t *cmd, *logi_cmd;
6517 6517 fc_local_port_t *port;
6518 6518 fc_remote_port_t *pd;
6519 6519 la_els_adisc_t *acc;
6520 6520 ls_code_t resp;
6521 6521 fc_hardaddr_t ha;
6522 6522 fc_portmap_t *changelist;
6523 6523 int initiator, adiscfail = 0;
6524 6524
6525 6525 pd = pkt->pkt_pd;
6526 6526 cmd = pkt->pkt_ulp_private;
6527 6527 port = cmd->cmd_port;
6528 6528
6529 6529 #ifndef __lock_lint
6530 6530 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6531 6531 #endif
6532 6532
6533 6533 ASSERT(pd != NULL && port != NULL && cmd != NULL);
6534 6534
6535 6535 mutex_enter(&port->fp_mutex);
6536 6536 port->fp_out_fpcmds--;
6537 6537 bailout = ((port->fp_statec_busy ||
6538 6538 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6539 6539 cmd->cmd_ulp_pkt) ? 1 : 0;
6540 6540 mutex_exit(&port->fp_mutex);
6541 6541
6542 6542 if (bailout) {
6543 6543 fp_iodone(cmd);
6544 6544 return;
6545 6545 }
6546 6546
6547 6547 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6548 6548 acc = (la_els_adisc_t *)pkt->pkt_resp;
6549 6549
6550 6550 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6551 6551 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6552 6552
6553 6553 if (resp.ls_code == LA_ELS_ACC) {
6554 6554 int is_private;
6555 6555
6556 6556 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
6557 6557 (uint8_t *)&acc->hard_addr, sizeof (ha),
6558 6558 DDI_DEV_AUTOINCR);
6559 6559
6560 6560 mutex_enter(&port->fp_mutex);
6561 6561
6562 6562 is_private =
6563 6563 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6564 6564
6565 6565 mutex_enter(&pd->pd_mutex);
6566 6566 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6567 6567 fctl_enlist_did_table(port, pd);
6568 6568 }
6569 6569 mutex_exit(&pd->pd_mutex);
6570 6570
6571 6571 mutex_exit(&port->fp_mutex);
6572 6572
6573 6573 mutex_enter(&pd->pd_mutex);
6574 6574 if (pd->pd_type != PORT_DEVICE_NEW) {
6575 6575 if (is_private && (pd->pd_hard_addr.hard_addr !=
6576 6576 ha.hard_addr)) {
6577 6577 pd->pd_type = PORT_DEVICE_CHANGED;
6578 6578 } else {
6579 6579 pd->pd_type = PORT_DEVICE_NOCHANGE;
6580 6580 }
6581 6581 }
6582 6582
6583 6583 if (is_private && (ha.hard_addr &&
6584 6584 pd->pd_port_id.port_id != ha.hard_addr)) {
6585 6585 char ww_name[17];
6586 6586
6587 6587 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6588 6588
6589 6589 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6590 6590 "NL_Port Identifier %x doesn't match"
6591 6591 " with Hard Address %x, Will use Port"
6592 6592 " WWN %s", pd->pd_port_id.port_id,
6593 6593 ha.hard_addr, ww_name);
6594 6594
6595 6595 pd->pd_hard_addr.hard_addr = 0;
6596 6596 } else {
6597 6597 pd->pd_hard_addr.hard_addr = ha.hard_addr;
6598 6598 }
6599 6599 mutex_exit(&pd->pd_mutex);
6600 6600 } else {
6601 6601 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6602 6602 return;
6603 6603 }
6604 6604 }
6605 6605 } else {
6606 6606 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6607 6607 return;
6608 6608 }
6609 6609
6610 6610 mutex_enter(&port->fp_mutex);
6611 6611 if (port->fp_statec_busy <= 1) {
6612 6612 mutex_exit(&port->fp_mutex);
6613 6613 if (pkt->pkt_state == FC_PKT_LS_RJT &&
6614 6614 pkt->pkt_reason == FC_REASON_CMD_UNABLE) {
6615 6615 uchar_t class;
6616 6616 int cmd_flag;
6617 6617 uint32_t src_id;
6618 6618
6619 6619 class = fp_get_nextclass(port,
6620 6620 FC_TRAN_CLASS_INVALID);
6621 6621 if (class == FC_TRAN_CLASS_INVALID) {
6622 6622 fp_iodone(cmd);
6623 6623 return;
6624 6624 }
6625 6625
6626 6626 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; "
6627 6627 "fp_state=0x%x, pkt_state=0x%x, "
6628 6628 "reason=0x%x, class=0x%x",
6629 6629 port->fp_state, pkt->pkt_state,
6630 6630 pkt->pkt_reason, class);
6631 6631 cmd_flag = FP_CMD_PLOGI_RETAIN;
6632 6632
6633 6633 logi_cmd = fp_alloc_pkt(port,
6634 6634 sizeof (la_els_logi_t),
6635 6635 sizeof (la_els_logi_t), KM_SLEEP, pd);
6636 6636 if (logi_cmd == NULL) {
6637 6637 fp_iodone(cmd);
6638 6638 return;
6639 6639 }
6640 6640
6641 6641 logi_cmd->cmd_pkt.pkt_tran_flags =
6642 6642 FC_TRAN_INTR | class;
6643 6643 logi_cmd->cmd_pkt.pkt_tran_type =
6644 6644 FC_PKT_EXCHANGE;
6645 6645 logi_cmd->cmd_flags = cmd_flag;
6646 6646 logi_cmd->cmd_retry_count = fp_retry_count;
6647 6647 logi_cmd->cmd_ulp_pkt = NULL;
6648 6648
6649 6649 mutex_enter(&port->fp_mutex);
6650 6650 src_id = port->fp_port_id.port_id;
6651 6651 mutex_exit(&port->fp_mutex);
6652 6652
6653 6653 fp_xlogi_init(port, logi_cmd, src_id,
6654 6654 pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr,
6655 6655 cmd->cmd_job, LA_ELS_PLOGI);
6656 6656 if (pd) {
6657 6657 mutex_enter(&pd->pd_mutex);
6658 6658 pd->pd_flags = PD_ELS_IN_PROGRESS;
6659 6659 mutex_exit(&pd->pd_mutex);
6660 6660 }
6661 6661
6662 6662 if (fp_sendcmd(port, logi_cmd,
6663 6663 port->fp_fca_handle) == FC_SUCCESS) {
6664 6664 fp_free_pkt(cmd);
6665 6665 return;
6666 6666 } else {
6667 6667 fp_free_pkt(logi_cmd);
6668 6668 }
6669 6669 } else {
6670 6670 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6671 6671 "ADISC to %x failed, cmd_flags=%x",
6672 6672 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6673 6673 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6674 6674 adiscfail = 1;
6675 6675 }
6676 6676 } else {
6677 6677 mutex_exit(&port->fp_mutex);
6678 6678 }
6679 6679 }
6680 6680
6681 6681 if (cmd->cmd_ulp_pkt) {
6682 6682 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6683 6683 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6684 6684 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6685 6685 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6686 6686 cmd->cmd_ulp_pkt->pkt_pd = pd;
6687 6687 FP_TRACE(FP_NHEAD1(9, 0),
6688 6688 "fp_adisc__intr;"
6689 6689 "ulp_pkt's pd is NULL, get a pd %p",
6690 6690 pd);
6691 6691
6692 6692 }
6693 6693 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6694 6694 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6695 6695 sizeof (fc_frame_hdr_t));
6696 6696 bcopy((caddr_t)pkt->pkt_resp,
6697 6697 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6698 6698 sizeof (la_els_adisc_t));
6699 6699 }
6700 6700
6701 6701 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6702 6702 FP_TRACE(FP_NHEAD1(9, 0),
6703 6703 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6704 6704 "fp_retry_count=%x, ulp_pkt=%p",
6705 6705 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6706 6706
6707 6707 mutex_enter(&port->fp_mutex);
6708 6708 mutex_enter(&pd->pd_mutex);
6709 6709
6710 6710 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6711 6711 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6712 6712 cmd->cmd_retry_count = fp_retry_count;
6713 6713
6714 6714 fp_logo_init(pd, cmd, cmd->cmd_job);
6715 6715
6716 6716 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6717 6717 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6718 6718
6719 6719 mutex_exit(&pd->pd_mutex);
6720 6720 mutex_exit(&port->fp_mutex);
6721 6721
6722 6722 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6723 6723 if (adiscfail) {
6724 6724 mutex_enter(&pd->pd_mutex);
6725 6725 initiator =
6726 6726 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
6727 6727 pd->pd_state = PORT_DEVICE_VALID;
6728 6728 pd->pd_aux_flags |= PD_LOGGED_OUT;
6729 6729 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6730 6730 pd->pd_type = PORT_DEVICE_NEW;
6731 6731 } else {
6732 6732 pd->pd_type = PORT_DEVICE_NOCHANGE;
6733 6733 }
6734 6734 mutex_exit(&pd->pd_mutex);
6735 6735
6736 6736 changelist =
6737 6737 kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6738 6738
6739 6739 if (initiator) {
6740 6740 fp_unregister_login(pd);
6741 6741 fctl_copy_portmap(changelist, pd);
6742 6742 } else {
6743 6743 fp_fillout_old_map(changelist, pd, 0);
6744 6744 }
6745 6745
6746 6746 FP_TRACE(FP_NHEAD1(9, 0),
6747 6747 "fp_adisc_intr: Dev change notification "
6748 6748 "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6749 6749 "map_flags=%x initiator=%d", port, pd,
6750 6750 changelist->map_type, changelist->map_state,
6751 6751 changelist->map_flags, initiator);
6752 6752
6753 6753 (void) fp_ulp_devc_cb(port, changelist,
6754 6754 1, 1, KM_SLEEP, 0);
6755 6755 }
6756 6756 if (rval == FC_SUCCESS) {
6757 6757 return;
6758 6758 }
6759 6759 }
6760 6760 fp_iodone(cmd);
6761 6761 }
6762 6762
6763 6763
6764 6764 /*
6765 6765 * Handle solicited LOGO response
6766 6766 */
6767 6767 static void
6768 6768 fp_logo_intr(fc_packet_t *pkt)
6769 6769 {
6770 6770 ls_code_t resp;
6771 6771 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6772 6772
6773 6773 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6774 6774 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6775 6775 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6776 6776
6777 6777 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6778 6778 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6779 6779
6780 6780 if (FP_IS_PKT_ERROR(pkt)) {
6781 6781 (void) fp_common_intr(pkt, 1);
6782 6782 return;
6783 6783 }
6784 6784
6785 6785 ASSERT(resp.ls_code == LA_ELS_ACC);
6786 6786 if (resp.ls_code != LA_ELS_ACC) {
6787 6787 (void) fp_common_intr(pkt, 1);
6788 6788 return;
6789 6789 }
6790 6790
6791 6791 if (pkt->pkt_pd != NULL) {
6792 6792 fp_unregister_login(pkt->pkt_pd);
6793 6793 }
6794 6794
6795 6795 fp_iodone(pkt->pkt_ulp_private);
6796 6796 }
6797 6797
6798 6798
6799 6799 /*
6800 6800 * Handle solicited RNID response
6801 6801 */
6802 6802 static void
6803 6803 fp_rnid_intr(fc_packet_t *pkt)
6804 6804 {
6805 6805 ls_code_t resp;
6806 6806 job_request_t *job;
6807 6807 fp_cmd_t *cmd;
6808 6808 la_els_rnid_acc_t *acc;
6809 6809 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6810 6810
6811 6811 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6812 6812 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6813 6813 cmd = pkt->pkt_ulp_private;
6814 6814
6815 6815 mutex_enter(&cmd->cmd_port->fp_mutex);
6816 6816 cmd->cmd_port->fp_out_fpcmds--;
6817 6817 mutex_exit(&cmd->cmd_port->fp_mutex);
6818 6818
6819 6819 job = cmd->cmd_job;
6820 6820 ASSERT(job->job_private != NULL);
6821 6821
6822 6822 /* If failure or LS_RJT then retry the packet, if needed */
6823 6823 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6824 6824 (void) fp_common_intr(pkt, 1);
6825 6825 return;
6826 6826 }
6827 6827
6828 6828 /* Save node_id memory allocated in ioctl code */
6829 6829 acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6830 6830
6831 6831 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6832 6832 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6833 6833
6834 6834 /* wakeup the ioctl thread and free the pkt */
6835 6835 fp_iodone(cmd);
6836 6836 }
6837 6837
6838 6838
6839 6839 /*
6840 6840 * Handle solicited RLS response
6841 6841 */
6842 6842 static void
6843 6843 fp_rls_intr(fc_packet_t *pkt)
6844 6844 {
6845 6845 ls_code_t resp;
6846 6846 job_request_t *job;
6847 6847 fp_cmd_t *cmd;
6848 6848 la_els_rls_acc_t *acc;
6849 6849 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6850 6850
6851 6851 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6852 6852 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6853 6853 cmd = pkt->pkt_ulp_private;
6854 6854
6855 6855 mutex_enter(&cmd->cmd_port->fp_mutex);
6856 6856 cmd->cmd_port->fp_out_fpcmds--;
6857 6857 mutex_exit(&cmd->cmd_port->fp_mutex);
6858 6858
6859 6859 job = cmd->cmd_job;
6860 6860 ASSERT(job->job_private != NULL);
6861 6861
6862 6862 /* If failure or LS_RJT then retry the packet, if needed */
6863 6863 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6864 6864 (void) fp_common_intr(pkt, 1);
6865 6865 return;
6866 6866 }
6867 6867
6868 6868 /* Save link error status block in memory allocated in ioctl code */
6869 6869 acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6870 6870
6871 6871 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6872 6872 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6873 6873 DDI_DEV_AUTOINCR);
6874 6874
6875 6875 /* wakeup the ioctl thread and free the pkt */
6876 6876 fp_iodone(cmd);
6877 6877 }
6878 6878
6879 6879
6880 6880 /*
6881 6881 * A solicited command completion interrupt (mostly for commands
6882 6882 * that require almost no post processing such as SCR ELS)
6883 6883 */
6884 6884 static void
6885 6885 fp_intr(fc_packet_t *pkt)
6886 6886 {
6887 6887 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6888 6888 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6889 6889 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6890 6890
6891 6891 if (FP_IS_PKT_ERROR(pkt)) {
6892 6892 (void) fp_common_intr(pkt, 1);
6893 6893 return;
6894 6894 }
6895 6895 fp_iodone(pkt->pkt_ulp_private);
6896 6896 }
6897 6897
6898 6898
6899 6899 /*
6900 6900 * Handle the underlying port's state change
6901 6901 */
6902 6902 static void
6903 6903 fp_statec_cb(opaque_t port_handle, uint32_t state)
6904 6904 {
6905 6905 fc_local_port_t *port = port_handle;
6906 6906 job_request_t *job;
6907 6907
6908 6908 /*
6909 6909 * If it is not possible to process the callbacks
6910 6910 * just drop the callback on the floor; Don't bother
6911 6911 * to do something that isn't safe at this time
6912 6912 */
6913 6913 mutex_enter(&port->fp_mutex);
6914 6914 if ((port->fp_soft_state &
6915 6915 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6916 6916 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6917 6917 mutex_exit(&port->fp_mutex);
6918 6918 return;
6919 6919 }
6920 6920
6921 6921 if (port->fp_statec_busy == 0) {
6922 6922 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6923 6923 #ifdef DEBUG
6924 6924 } else {
6925 6925 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6926 6926 #endif
6927 6927 }
6928 6928
6929 6929 port->fp_statec_busy++;
6930 6930
6931 6931 /*
6932 6932 * For now, force the trusted method of device authentication (by
6933 6933 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6934 6934 */
6935 6935 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6936 6936 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6937 6937 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6938 6938 fp_port_offline(port, 0);
6939 6939 }
6940 6940 mutex_exit(&port->fp_mutex);
6941 6941
6942 6942 switch (FC_PORT_STATE_MASK(state)) {
6943 6943 case FC_STATE_OFFLINE:
6944 6944 job = fctl_alloc_job(JOB_PORT_OFFLINE,
6945 6945 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6946 6946 if (job == NULL) {
6947 6947 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6948 6948 " fp_statec_cb() couldn't submit a job "
6949 6949 " to the thread: failing..");
6950 6950 mutex_enter(&port->fp_mutex);
6951 6951 if (--port->fp_statec_busy == 0) {
6952 6952 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6953 6953 }
6954 6954 mutex_exit(&port->fp_mutex);
6955 6955 return;
6956 6956 }
6957 6957 mutex_enter(&port->fp_mutex);
6958 6958 /*
6959 6959 * Zero out this field so that we do not retain
6960 6960 * the fabric name as its no longer valid
6961 6961 */
6962 6962 bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6963 6963 port->fp_state = state;
6964 6964 mutex_exit(&port->fp_mutex);
6965 6965
6966 6966 fctl_enque_job(port, job);
6967 6967 break;
6968 6968
6969 6969 case FC_STATE_ONLINE:
6970 6970 case FC_STATE_LOOP:
6971 6971 mutex_enter(&port->fp_mutex);
6972 6972 port->fp_state = state;
6973 6973
6974 6974 if (port->fp_offline_tid) {
6975 6975 timeout_id_t tid;
6976 6976
6977 6977 tid = port->fp_offline_tid;
6978 6978 port->fp_offline_tid = NULL;
6979 6979 mutex_exit(&port->fp_mutex);
6980 6980 (void) untimeout(tid);
6981 6981 } else {
6982 6982 mutex_exit(&port->fp_mutex);
6983 6983 }
6984 6984
6985 6985 job = fctl_alloc_job(JOB_PORT_ONLINE,
6986 6986 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6987 6987 if (job == NULL) {
6988 6988 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6989 6989 "fp_statec_cb() couldn't submit a job "
6990 6990 "to the thread: failing..");
6991 6991
6992 6992 mutex_enter(&port->fp_mutex);
6993 6993 if (--port->fp_statec_busy == 0) {
6994 6994 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6995 6995 }
6996 6996 mutex_exit(&port->fp_mutex);
6997 6997 return;
6998 6998 }
6999 6999 fctl_enque_job(port, job);
7000 7000 break;
7001 7001
7002 7002 case FC_STATE_RESET_REQUESTED:
7003 7003 mutex_enter(&port->fp_mutex);
7004 7004 port->fp_state = FC_STATE_OFFLINE;
7005 7005 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
7006 7006 mutex_exit(&port->fp_mutex);
7007 7007 /* FALLTHROUGH */
7008 7008
7009 7009 case FC_STATE_RESET:
7010 7010 job = fctl_alloc_job(JOB_ULP_NOTIFY,
7011 7011 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
7012 7012 if (job == NULL) {
7013 7013 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
7014 7014 "fp_statec_cb() couldn't submit a job"
7015 7015 " to the thread: failing..");
7016 7016
7017 7017 mutex_enter(&port->fp_mutex);
7018 7018 if (--port->fp_statec_busy == 0) {
7019 7019 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7020 7020 }
7021 7021 mutex_exit(&port->fp_mutex);
7022 7022 return;
7023 7023 }
7024 7024
7025 7025 /* squeeze into some field in the job structure */
7026 7026 job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
7027 7027 fctl_enque_job(port, job);
7028 7028 break;
7029 7029
7030 7030 case FC_STATE_TARGET_PORT_RESET:
7031 7031 (void) fp_ulp_notify(port, state, KM_NOSLEEP);
7032 7032 /* FALLTHROUGH */
7033 7033
7034 7034 case FC_STATE_NAMESERVICE:
7035 7035 /* FALLTHROUGH */
7036 7036
7037 7037 default:
7038 7038 mutex_enter(&port->fp_mutex);
7039 7039 if (--port->fp_statec_busy == 0) {
7040 7040 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7041 7041 }
7042 7042 mutex_exit(&port->fp_mutex);
7043 7043 break;
7044 7044 }
7045 7045 }
7046 7046
7047 7047
7048 7048 /*
7049 7049 * Register with the Name Server for RSCNs
7050 7050 */
7051 7051 static int
7052 7052 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
7053 7053 int sleep)
7054 7054 {
7055 7055 uint32_t s_id;
7056 7056 uchar_t class;
7057 7057 fc_scr_req_t payload;
7058 7058 fp_cmd_t *cmd;
7059 7059 fc_packet_t *pkt;
7060 7060
7061 7061 mutex_enter(&port->fp_mutex);
7062 7062 s_id = port->fp_port_id.port_id;
7063 7063 class = port->fp_ns_login_class;
7064 7064 mutex_exit(&port->fp_mutex);
7065 7065
7066 7066 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
7067 7067 sizeof (fc_scr_resp_t), sleep, NULL);
7068 7068 if (cmd == NULL) {
7069 7069 return (FC_NOMEM);
7070 7070 }
7071 7071
7072 7072 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
7073 7073 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
7074 7074 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
7075 7075 cmd->cmd_retry_count = fp_retry_count;
7076 7076 cmd->cmd_ulp_pkt = NULL;
7077 7077
7078 7078 pkt = &cmd->cmd_pkt;
7079 7079 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
7080 7080
7081 7081 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
7082 7082
7083 7083 payload.ls_code.ls_code = LA_ELS_SCR;
7084 7084 payload.ls_code.mbz = 0;
7085 7085 payload.scr_rsvd = 0;
7086 7086 payload.scr_func = scr_func;
7087 7087
7088 7088 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
7089 7089 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
7090 7090
7091 7091 job->job_counter = 1;
7092 7092
7093 7093 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
7094 7094 fp_iodone(cmd);
7095 7095 }
7096 7096
7097 7097 return (FC_SUCCESS);
7098 7098 }
7099 7099
7100 7100
7101 7101 /*
7102 7102 * There are basically two methods to determine the total number of
7103 7103 * devices out in the NS database; Reading the details of the two
7104 7104 * methods described below, it shouldn't be hard to identify which
7105 7105 * of the two methods is better.
7106 7106 *
7107 7107 * Method 1.
7108 7108 * Iteratively issue GANs until all ports identifiers are walked
7109 7109 *
7110 7110 * Method 2.
7111 7111 * Issue GID_PT (get port Identifiers) with Maximum residual
7112 7112 * field in the request CT HEADER set to accommodate only the
7113 7113 * CT HEADER in the response frame. And if FC-GS2 has been
7114 7114 * carefully read, the NS here has a chance to FS_ACC the
7115 7115 * request and indicate the residual size in the FS_ACC.
7116 7116 *
7117 7117 * Method 2 is wonderful, although it's not mandatory for the NS
7118 7118 * to update the Maximum/Residual Field as can be seen in 4.3.1.6
7119 7119 * (note with particular care the use of the auxiliary verb 'may')
7120 7120 *
7121 7121 */
7122 7122 static int
7123 7123 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
7124 7124 int sleep)
7125 7125 {
7126 7126 int flags;
7127 7127 int rval;
7128 7128 uint32_t src_id;
7129 7129 fctl_ns_req_t *ns_cmd;
7130 7130
7131 7131 ASSERT(!MUTEX_HELD(&port->fp_mutex));
7132 7132
7133 7133 mutex_enter(&port->fp_mutex);
7134 7134 src_id = port->fp_port_id.port_id;
7135 7135 mutex_exit(&port->fp_mutex);
7136 7136
7137 7137 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7138 7138 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
7139 7139 sizeof (ns_resp_gid_pt_t), 0,
7140 7140 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
7141 7141
7142 7142 if (ns_cmd == NULL) {
7143 7143 return (FC_NOMEM);
7144 7144 }
7145 7145
7146 7146 ns_cmd->ns_cmd_code = NS_GID_PT;
7147 7147 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
7148 7148 = FC_NS_PORT_NX; /* All port types */
7149 7149 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
7150 7150
7151 7151 } else {
7152 7152 uint32_t ns_flags;
7153 7153
7154 7154 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
7155 7155 if (create) {
7156 7156 ns_flags |= FCTL_NS_CREATE_DEVICE;
7157 7157 }
7158 7158 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
7159 7159 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
7160 7160
7161 7161 if (ns_cmd == NULL) {
7162 7162 return (FC_NOMEM);
7163 7163 }
7164 7164 ns_cmd->ns_gan_index = 0;
7165 7165 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
7166 7166 ns_cmd->ns_cmd_code = NS_GA_NXT;
7167 7167 ns_cmd->ns_gan_max = 0xFFFF;
7168 7168
7169 7169 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
7170 7170 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
7171 7171 }
7172 7172
7173 7173 flags = job->job_flags;
7174 7174 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
7175 7175 job->job_counter = 1;
7176 7176
7177 7177 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
7178 7178 job->job_flags = flags;
7179 7179
7180 7180 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7181 7181 uint16_t max_resid;
7182 7182
7183 7183 /*
7184 7184 * Revert to scanning the NS if NS_GID_PT isn't
7185 7185 * helping us figure out total number of devices.
7186 7186 */
7187 7187 if (job->job_result != FC_SUCCESS ||
7188 7188 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
7189 7189 mutex_enter(&port->fp_mutex);
7190 7190 port->fp_options &= ~FP_NS_SMART_COUNT;
7191 7191 mutex_exit(&port->fp_mutex);
7192 7192
7193 7193 fctl_free_ns_cmd(ns_cmd);
7194 7194 return (fp_ns_get_devcount(port, job, create, sleep));
7195 7195 }
7196 7196
7197 7197 mutex_enter(&port->fp_mutex);
7198 7198 port->fp_total_devices = 1;
7199 7199 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7200 7200 if (max_resid) {
7201 7201 /*
7202 7202 * Since port identifier is 4 bytes and max_resid
7203 7203 * is also in WORDS, max_resid simply indicates
7204 7204 * the total number of port identifiers not
7205 7205 * transferred
7206 7206 */
7207 7207 port->fp_total_devices += max_resid;
7208 7208 }
7209 7209 mutex_exit(&port->fp_mutex);
7210 7210 }
7211 7211 mutex_enter(&port->fp_mutex);
7212 7212 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7213 7213 mutex_exit(&port->fp_mutex);
7214 7214 fctl_free_ns_cmd(ns_cmd);
7215 7215
7216 7216 return (rval);
7217 7217 }
7218 7218
7219 7219 /*
7220 7220 * One heck of a function to serve userland.
7221 7221 */
7222 7222 static int
7223 7223 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7224 7224 {
7225 7225 int rval = 0;
7226 7226 int jcode;
7227 7227 uint32_t ret;
7228 7228 uchar_t open_flag;
7229 7229 fcio_t *kfcio;
7230 7230 job_request_t *job;
7231 7231 boolean_t use32 = B_FALSE;
7232 7232
7233 7233 #ifdef _MULTI_DATAMODEL
7234 7234 switch (ddi_model_convert_from(mode & FMODELS)) {
7235 7235 case DDI_MODEL_ILP32:
7236 7236 use32 = B_TRUE;
7237 7237 break;
7238 7238
7239 7239 case DDI_MODEL_NONE:
7240 7240 default:
7241 7241 break;
7242 7242 }
7243 7243 #endif
7244 7244
7245 7245 mutex_enter(&port->fp_mutex);
7246 7246 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7247 7247 FP_SOFT_IN_UNSOL_CB)) {
7248 7248 fcio->fcio_errno = FC_STATEC_BUSY;
7249 7249 mutex_exit(&port->fp_mutex);
7250 7250 rval = EAGAIN;
7251 7251 if (fp_fcio_copyout(fcio, data, mode)) {
7252 7252 rval = EFAULT;
7253 7253 }
7254 7254 return (rval);
7255 7255 }
7256 7256 open_flag = port->fp_flag;
7257 7257 mutex_exit(&port->fp_mutex);
7258 7258
7259 7259 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7260 7260 fcio->fcio_errno = FC_FAILURE;
7261 7261 rval = EACCES;
7262 7262 if (fp_fcio_copyout(fcio, data, mode)) {
7263 7263 rval = EFAULT;
7264 7264 }
7265 7265 return (rval);
7266 7266 }
7267 7267
7268 7268 /*
7269 7269 * If an exclusive open was demanded during open, don't let
7270 7270 * either innocuous or devil threads to share the file
7271 7271 * descriptor and fire down exclusive access commands
7272 7272 */
7273 7273 mutex_enter(&port->fp_mutex);
7274 7274 if (port->fp_flag & FP_EXCL) {
7275 7275 if (port->fp_flag & FP_EXCL_BUSY) {
7276 7276 mutex_exit(&port->fp_mutex);
7277 7277 fcio->fcio_errno = FC_FAILURE;
7278 7278 return (EBUSY);
7279 7279 }
7280 7280 port->fp_flag |= FP_EXCL_BUSY;
7281 7281 }
7282 7282 mutex_exit(&port->fp_mutex);
7283 7283
7284 7284 fcio->fcio_errno = FC_SUCCESS;
7285 7285
7286 7286 switch (fcio->fcio_cmd) {
7287 7287 case FCIO_GET_HOST_PARAMS: {
7288 7288 fc_port_dev_t *val;
7289 7289 fc_port_dev32_t *val32;
7290 7290 int index;
7291 7291 int lilp_device_count;
7292 7292 fc_lilpmap_t *lilp_map;
7293 7293 uchar_t *alpa_list;
7294 7294
7295 7295 if (use32 == B_TRUE) {
7296 7296 if (fcio->fcio_olen != sizeof (*val32) ||
7297 7297 fcio->fcio_xfer != FCIO_XFER_READ) {
7298 7298 rval = EINVAL;
7299 7299 break;
7300 7300 }
7301 7301 } else {
7302 7302 if (fcio->fcio_olen != sizeof (*val) ||
7303 7303 fcio->fcio_xfer != FCIO_XFER_READ) {
7304 7304 rval = EINVAL;
7305 7305 break;
7306 7306 }
7307 7307 }
7308 7308
7309 7309 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7310 7310
7311 7311 mutex_enter(&port->fp_mutex);
7312 7312 val->dev_did = port->fp_port_id;
7313 7313 val->dev_hard_addr = port->fp_hard_addr;
7314 7314 val->dev_pwwn = port->fp_service_params.nport_ww_name;
7315 7315 val->dev_nwwn = port->fp_service_params.node_ww_name;
7316 7316 val->dev_state = port->fp_state;
7317 7317
7318 7318 lilp_map = &port->fp_lilp_map;
7319 7319 alpa_list = &lilp_map->lilp_alpalist[0];
7320 7320 lilp_device_count = lilp_map->lilp_length;
7321 7321 for (index = 0; index < lilp_device_count; index++) {
7322 7322 uint32_t d_id;
7323 7323
7324 7324 d_id = alpa_list[index];
7325 7325 if (d_id == port->fp_port_id.port_id) {
7326 7326 break;
7327 7327 }
7328 7328 }
7329 7329 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7330 7330
7331 7331 bcopy(port->fp_fc4_types, val->dev_type,
7332 7332 sizeof (port->fp_fc4_types));
7333 7333 mutex_exit(&port->fp_mutex);
7334 7334
7335 7335 if (use32 == B_TRUE) {
7336 7336 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7337 7337
7338 7338 val32->dev_did = val->dev_did;
7339 7339 val32->dev_hard_addr = val->dev_hard_addr;
7340 7340 val32->dev_pwwn = val->dev_pwwn;
7341 7341 val32->dev_nwwn = val->dev_nwwn;
7342 7342 val32->dev_state = val->dev_state;
7343 7343 val32->dev_did.priv_lilp_posit =
7344 7344 val->dev_did.priv_lilp_posit;
7345 7345
7346 7346 bcopy(val->dev_type, val32->dev_type,
7347 7347 sizeof (port->fp_fc4_types));
7348 7348
7349 7349 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7350 7350 fcio->fcio_olen, mode) == 0) {
7351 7351 if (fp_fcio_copyout(fcio, data, mode)) {
7352 7352 rval = EFAULT;
7353 7353 }
7354 7354 } else {
7355 7355 rval = EFAULT;
7356 7356 }
7357 7357
7358 7358 kmem_free(val32, sizeof (*val32));
7359 7359 } else {
7360 7360 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7361 7361 fcio->fcio_olen, mode) == 0) {
7362 7362 if (fp_fcio_copyout(fcio, data, mode)) {
7363 7363 rval = EFAULT;
7364 7364 }
7365 7365 } else {
7366 7366 rval = EFAULT;
7367 7367 }
7368 7368 }
7369 7369
7370 7370 /* need to free "val" here */
7371 7371 kmem_free(val, sizeof (*val));
7372 7372 break;
7373 7373 }
7374 7374
7375 7375 case FCIO_GET_OTHER_ADAPTER_PORTS: {
7376 7376 uint32_t index;
7377 7377 char *tmpPath;
7378 7378 fc_local_port_t *tmpPort;
7379 7379
7380 7380 if (fcio->fcio_olen < MAXPATHLEN ||
7381 7381 fcio->fcio_ilen != sizeof (uint32_t)) {
7382 7382 rval = EINVAL;
7383 7383 break;
7384 7384 }
7385 7385 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7386 7386 rval = EFAULT;
7387 7387 break;
7388 7388 }
7389 7389
7390 7390 tmpPort = fctl_get_adapter_port_by_index(port, index);
7391 7391 if (tmpPort == NULL) {
7392 7392 FP_TRACE(FP_NHEAD1(9, 0),
7393 7393 "User supplied index out of range");
7394 7394 fcio->fcio_errno = FC_BADPORT;
7395 7395 rval = EFAULT;
7396 7396 if (fp_fcio_copyout(fcio, data, mode)) {
7397 7397 rval = EFAULT;
7398 7398 }
7399 7399 break;
7400 7400 }
7401 7401
7402 7402 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7403 7403 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7404 7404 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7405 7405 MAXPATHLEN, mode) == 0) {
7406 7406 if (fp_fcio_copyout(fcio, data, mode)) {
7407 7407 rval = EFAULT;
7408 7408 }
7409 7409 } else {
7410 7410 rval = EFAULT;
7411 7411 }
7412 7412 kmem_free(tmpPath, MAXPATHLEN);
7413 7413 break;
7414 7414 }
7415 7415
7416 7416 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7417 7417 case FCIO_GET_ADAPTER_ATTRIBUTES: {
7418 7418 fc_hba_adapter_attributes_t *val;
7419 7419 fc_hba_adapter_attributes32_t *val32;
7420 7420
7421 7421 if (use32 == B_TRUE) {
7422 7422 if (fcio->fcio_olen < sizeof (*val32) ||
7423 7423 fcio->fcio_xfer != FCIO_XFER_READ) {
7424 7424 rval = EINVAL;
7425 7425 break;
7426 7426 }
7427 7427 } else {
7428 7428 if (fcio->fcio_olen < sizeof (*val) ||
7429 7429 fcio->fcio_xfer != FCIO_XFER_READ) {
7430 7430 rval = EINVAL;
7431 7431 break;
7432 7432 }
7433 7433 }
7434 7434
7435 7435 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7436 7436 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7437 7437 mutex_enter(&port->fp_mutex);
7438 7438 bcopy(port->fp_hba_port_attrs.manufacturer,
7439 7439 val->Manufacturer,
7440 7440 sizeof (val->Manufacturer));
7441 7441 bcopy(port->fp_hba_port_attrs.serial_number,
7442 7442 val->SerialNumber,
7443 7443 sizeof (val->SerialNumber));
7444 7444 bcopy(port->fp_hba_port_attrs.model,
7445 7445 val->Model,
7446 7446 sizeof (val->Model));
7447 7447 bcopy(port->fp_hba_port_attrs.model_description,
7448 7448 val->ModelDescription,
7449 7449 sizeof (val->ModelDescription));
7450 7450 bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7451 7451 port->fp_sym_node_namelen);
7452 7452 bcopy(port->fp_hba_port_attrs.hardware_version,
7453 7453 val->HardwareVersion,
7454 7454 sizeof (val->HardwareVersion));
7455 7455 bcopy(port->fp_hba_port_attrs.option_rom_version,
7456 7456 val->OptionROMVersion,
7457 7457 sizeof (val->OptionROMVersion));
7458 7458 bcopy(port->fp_hba_port_attrs.firmware_version,
7459 7459 val->FirmwareVersion,
7460 7460 sizeof (val->FirmwareVersion));
7461 7461 val->VendorSpecificID =
7462 7462 port->fp_hba_port_attrs.vendor_specific_id;
7463 7463 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7464 7464 &val->NodeWWN.raw_wwn,
7465 7465 sizeof (val->NodeWWN.raw_wwn));
7466 7466
7467 7467
7468 7468 bcopy(port->fp_hba_port_attrs.driver_name,
7469 7469 val->DriverName,
7470 7470 sizeof (val->DriverName));
7471 7471 bcopy(port->fp_hba_port_attrs.driver_version,
7472 7472 val->DriverVersion,
7473 7473 sizeof (val->DriverVersion));
7474 7474 mutex_exit(&port->fp_mutex);
7475 7475
7476 7476 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7477 7477 val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7478 7478 } else {
7479 7479 val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7480 7480 }
7481 7481
7482 7482 if (use32 == B_TRUE) {
7483 7483 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7484 7484 val32->version = val->version;
7485 7485 bcopy(val->Manufacturer, val32->Manufacturer,
7486 7486 sizeof (val->Manufacturer));
7487 7487 bcopy(val->SerialNumber, val32->SerialNumber,
7488 7488 sizeof (val->SerialNumber));
7489 7489 bcopy(val->Model, val32->Model,
7490 7490 sizeof (val->Model));
7491 7491 bcopy(val->ModelDescription, val32->ModelDescription,
7492 7492 sizeof (val->ModelDescription));
7493 7493 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7494 7494 sizeof (val->NodeSymbolicName));
7495 7495 bcopy(val->HardwareVersion, val32->HardwareVersion,
7496 7496 sizeof (val->HardwareVersion));
7497 7497 bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7498 7498 sizeof (val->OptionROMVersion));
7499 7499 bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7500 7500 sizeof (val->FirmwareVersion));
7501 7501 val32->VendorSpecificID = val->VendorSpecificID;
7502 7502 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7503 7503 sizeof (val->NodeWWN.raw_wwn));
7504 7504 bcopy(val->DriverName, val32->DriverName,
7505 7505 sizeof (val->DriverName));
7506 7506 bcopy(val->DriverVersion, val32->DriverVersion,
7507 7507 sizeof (val->DriverVersion));
7508 7508
7509 7509 val32->NumberOfPorts = val->NumberOfPorts;
7510 7510
7511 7511 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7512 7512 fcio->fcio_olen, mode) == 0) {
7513 7513 if (fp_fcio_copyout(fcio, data, mode)) {
7514 7514 rval = EFAULT;
7515 7515 }
7516 7516 } else {
7517 7517 rval = EFAULT;
7518 7518 }
7519 7519
7520 7520 kmem_free(val32, sizeof (*val32));
7521 7521 } else {
7522 7522 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7523 7523 fcio->fcio_olen, mode) == 0) {
7524 7524 if (fp_fcio_copyout(fcio, data, mode)) {
7525 7525 rval = EFAULT;
7526 7526 }
7527 7527 } else {
7528 7528 rval = EFAULT;
7529 7529 }
7530 7530 }
7531 7531
7532 7532 kmem_free(val, sizeof (*val));
7533 7533 break;
7534 7534 }
7535 7535
7536 7536 case FCIO_GET_NPIV_ATTRIBUTES: {
7537 7537 fc_hba_npiv_attributes_t *attrs;
7538 7538
7539 7539 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7540 7540 mutex_enter(&port->fp_mutex);
7541 7541 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7542 7542 &attrs->NodeWWN.raw_wwn,
7543 7543 sizeof (attrs->NodeWWN.raw_wwn));
7544 7544 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7545 7545 &attrs->PortWWN.raw_wwn,
7546 7546 sizeof (attrs->PortWWN.raw_wwn));
7547 7547 mutex_exit(&port->fp_mutex);
7548 7548 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7549 7549 fcio->fcio_olen, mode) == 0) {
7550 7550 if (fp_fcio_copyout(fcio, data, mode)) {
7551 7551 rval = EFAULT;
7552 7552 }
7553 7553 } else {
7554 7554 rval = EFAULT;
7555 7555 }
7556 7556 kmem_free(attrs, sizeof (*attrs));
7557 7557 break;
7558 7558 }
7559 7559
7560 7560 case FCIO_DELETE_NPIV_PORT: {
7561 7561 fc_local_port_t *tmpport;
7562 7562 char ww_pname[17];
7563 7563 la_wwn_t vwwn[1];
7564 7564
7565 7565 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7566 7566 if (ddi_copyin(fcio->fcio_ibuf,
7567 7567 &vwwn, sizeof (la_wwn_t), mode)) {
7568 7568 rval = EFAULT;
7569 7569 break;
7570 7570 }
7571 7571
7572 7572 fc_wwn_to_str(&vwwn[0], ww_pname);
7573 7573 FP_TRACE(FP_NHEAD1(3, 0),
7574 7574 "Delete NPIV Port %s", ww_pname);
7575 7575 tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7576 7576 if (tmpport == NULL) {
7577 7577 FP_TRACE(FP_NHEAD1(3, 0),
7578 7578 "Delete NPIV Port : no found");
7579 7579 rval = EFAULT;
7580 7580 } else {
7581 7581 fc_local_port_t *nextport = tmpport->fp_port_next;
7582 7582 fc_local_port_t *prevport = tmpport->fp_port_prev;
7583 7583 int portlen, portindex, ret;
7584 7584
7585 7585 portlen = sizeof (portindex);
7586 7586 ret = ddi_prop_op(DDI_DEV_T_ANY,
7587 7587 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7588 7588 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7589 7589 (caddr_t)&portindex, &portlen);
7590 7590 if (ret != DDI_SUCCESS) {
7591 7591 rval = EFAULT;
7592 7592 break;
7593 7593 }
7594 7594 if (ndi_devi_offline(tmpport->fp_port_dip,
7595 7595 NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7596 7596 FP_TRACE(FP_NHEAD1(1, 0),
7597 7597 "Delete NPIV Port failed");
7598 7598 mutex_enter(&port->fp_mutex);
7599 7599 tmpport->fp_npiv_state = 0;
7600 7600 mutex_exit(&port->fp_mutex);
7601 7601 rval = EFAULT;
7602 7602 } else {
7603 7603 mutex_enter(&port->fp_mutex);
7604 7604 nextport->fp_port_prev = prevport;
7605 7605 prevport->fp_port_next = nextport;
7606 7606 if (port == port->fp_port_next) {
7607 7607 port->fp_port_next =
7608 7608 port->fp_port_prev = NULL;
7609 7609 }
7610 7610 port->fp_npiv_portnum--;
7611 7611 FP_TRACE(FP_NHEAD1(3, 0),
7612 7612 "Delete NPIV Port %d", portindex);
7613 7613 port->fp_npiv_portindex[portindex-1] = 0;
7614 7614 mutex_exit(&port->fp_mutex);
7615 7615 }
7616 7616 }
7617 7617 break;
7618 7618 }
7619 7619
7620 7620 case FCIO_CREATE_NPIV_PORT: {
7621 7621 char ww_nname[17], ww_pname[17];
7622 7622 la_npiv_create_entry_t entrybuf;
7623 7623 uint32_t vportindex = 0;
7624 7624 int npiv_ret = 0;
7625 7625 char *portname, *fcaname;
7626 7626
7627 7627 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7628 7628 (void) ddi_pathname(port->fp_port_dip, portname);
7629 7629 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7630 7630 (void) ddi_pathname(port->fp_fca_dip, fcaname);
7631 7631 FP_TRACE(FP_NHEAD1(1, 0),
7632 7632 "Create NPIV port %s %s %s", portname, fcaname,
7633 7633 ddi_driver_name(port->fp_fca_dip));
7634 7634 kmem_free(portname, MAXPATHLEN);
7635 7635 kmem_free(fcaname, MAXPATHLEN);
7636 7636 if (ddi_copyin(fcio->fcio_ibuf,
7637 7637 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7638 7638 rval = EFAULT;
7639 7639 break;
7640 7640 }
7641 7641
7642 7642 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7643 7643 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7644 7644 vportindex = entrybuf.vindex;
7645 7645 FP_TRACE(FP_NHEAD1(3, 0),
7646 7646 "Create NPIV Port %s %s %d",
7647 7647 ww_nname, ww_pname, vportindex);
7648 7648
7649 7649 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7650 7650 rval = EFAULT;
7651 7651 break;
7652 7652 }
7653 7653 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7654 7654 port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7655 7655 if (npiv_ret == NDI_SUCCESS) {
7656 7656 mutex_enter(&port->fp_mutex);
7657 7657 port->fp_npiv_portnum++;
7658 7658 mutex_exit(&port->fp_mutex);
7659 7659 if (fp_copyout((void *)&vportindex,
7660 7660 (void *)fcio->fcio_obuf,
7661 7661 fcio->fcio_olen, mode) == 0) {
7662 7662 if (fp_fcio_copyout(fcio, data, mode)) {
7663 7663 rval = EFAULT;
7664 7664 }
7665 7665 } else {
7666 7666 rval = EFAULT;
7667 7667 }
7668 7668 } else {
7669 7669 rval = EFAULT;
7670 7670 }
7671 7671 FP_TRACE(FP_NHEAD1(3, 0),
7672 7672 "Create NPIV Port %d %d", npiv_ret, vportindex);
7673 7673 break;
7674 7674 }
7675 7675
7676 7676 case FCIO_GET_NPIV_PORT_LIST: {
7677 7677 fc_hba_npiv_port_list_t *list;
7678 7678 int count;
7679 7679
7680 7680 if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7681 7681 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7682 7682 rval = EINVAL;
7683 7683 break;
7684 7684 }
7685 7685
7686 7686 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7687 7687 list->version = FC_HBA_LIST_VERSION;
7688 7688
7689 7689 count = (fcio->fcio_olen -
7690 7690 (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN + 1;
7691 7691 if (port->fp_npiv_portnum > count) {
7692 7692 list->numAdapters = port->fp_npiv_portnum;
7693 7693 } else {
7694 7694 /* build npiv port list */
7695 7695 count = fc_ulp_get_npiv_port_list(port,
7696 7696 (char *)list->hbaPaths);
7697 7697 if (count < 0) {
7698 7698 rval = ENXIO;
7699 7699 FP_TRACE(FP_NHEAD1(1, 0),
7700 7700 "Build NPIV Port List error");
7701 7701 kmem_free(list, fcio->fcio_olen);
7702 7702 break;
7703 7703 }
7704 7704 list->numAdapters = count;
7705 7705 }
7706 7706
7707 7707 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7708 7708 fcio->fcio_olen, mode) == 0) {
7709 7709 if (fp_fcio_copyout(fcio, data, mode)) {
7710 7710 FP_TRACE(FP_NHEAD1(1, 0),
7711 7711 "Copy NPIV Port data error");
7712 7712 rval = EFAULT;
7713 7713 }
7714 7714 } else {
7715 7715 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7716 7716 rval = EFAULT;
7717 7717 }
7718 7718 kmem_free(list, fcio->fcio_olen);
7719 7719 break;
7720 7720 }
7721 7721
7722 7722 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7723 7723 fc_hba_port_npiv_attributes_t *val;
7724 7724
7725 7725 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7726 7726 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7727 7727
7728 7728 mutex_enter(&port->fp_mutex);
7729 7729 val->npivflag = port->fp_npiv_flag;
7730 7730 val->lastChange = port->fp_last_change;
7731 7731 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7732 7732 &val->PortWWN.raw_wwn,
7733 7733 sizeof (val->PortWWN.raw_wwn));
7734 7734 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7735 7735 &val->NodeWWN.raw_wwn,
7736 7736 sizeof (val->NodeWWN.raw_wwn));
7737 7737 mutex_exit(&port->fp_mutex);
7738 7738
7739 7739 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7740 7740 if (port->fp_npiv_type != FC_NPIV_PORT) {
7741 7741 val->MaxNumberOfNPIVPorts =
7742 7742 port->fp_fca_tran->fca_num_npivports;
7743 7743 } else {
7744 7744 val->MaxNumberOfNPIVPorts = 0;
7745 7745 }
7746 7746
7747 7747 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7748 7748 fcio->fcio_olen, mode) == 0) {
7749 7749 if (fp_fcio_copyout(fcio, data, mode)) {
7750 7750 rval = EFAULT;
7751 7751 }
7752 7752 } else {
7753 7753 rval = EFAULT;
7754 7754 }
7755 7755 kmem_free(val, sizeof (*val));
7756 7756 break;
7757 7757 }
7758 7758
7759 7759 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7760 7760 fc_hba_port_attributes_t *val;
7761 7761 fc_hba_port_attributes32_t *val32;
7762 7762
7763 7763 if (use32 == B_TRUE) {
7764 7764 if (fcio->fcio_olen < sizeof (*val32) ||
7765 7765 fcio->fcio_xfer != FCIO_XFER_READ) {
7766 7766 rval = EINVAL;
7767 7767 break;
7768 7768 }
7769 7769 } else {
7770 7770 if (fcio->fcio_olen < sizeof (*val) ||
7771 7771 fcio->fcio_xfer != FCIO_XFER_READ) {
7772 7772 rval = EINVAL;
7773 7773 break;
7774 7774 }
7775 7775 }
7776 7776
7777 7777 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7778 7778 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7779 7779 mutex_enter(&port->fp_mutex);
7780 7780 val->lastChange = port->fp_last_change;
7781 7781 val->fp_minor = port->fp_instance;
7782 7782
7783 7783 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7784 7784 &val->PortWWN.raw_wwn,
7785 7785 sizeof (val->PortWWN.raw_wwn));
7786 7786 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7787 7787 &val->NodeWWN.raw_wwn,
7788 7788 sizeof (val->NodeWWN.raw_wwn));
7789 7789 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7790 7790 sizeof (val->FabricName.raw_wwn));
7791 7791
7792 7792 val->PortFcId = port->fp_port_id.port_id;
7793 7793
7794 7794 switch (FC_PORT_STATE_MASK(port->fp_state)) {
7795 7795 case FC_STATE_OFFLINE:
7796 7796 val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7797 7797 break;
7798 7798 case FC_STATE_ONLINE:
7799 7799 case FC_STATE_LOOP:
7800 7800 case FC_STATE_NAMESERVICE:
7801 7801 val->PortState = FC_HBA_PORTSTATE_ONLINE;
7802 7802 break;
7803 7803 default:
7804 7804 val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7805 7805 break;
7806 7806 }
7807 7807
7808 7808 /* Translate from LV to FC-HBA port type codes */
7809 7809 switch (port->fp_port_type.port_type) {
7810 7810 case FC_NS_PORT_N:
7811 7811 val->PortType = FC_HBA_PORTTYPE_NPORT;
7812 7812 break;
7813 7813 case FC_NS_PORT_NL:
7814 7814 /* Actually means loop for us */
7815 7815 val->PortType = FC_HBA_PORTTYPE_LPORT;
7816 7816 break;
7817 7817 case FC_NS_PORT_F:
7818 7818 val->PortType = FC_HBA_PORTTYPE_FPORT;
7819 7819 break;
7820 7820 case FC_NS_PORT_FL:
7821 7821 val->PortType = FC_HBA_PORTTYPE_FLPORT;
7822 7822 break;
7823 7823 case FC_NS_PORT_E:
7824 7824 val->PortType = FC_HBA_PORTTYPE_EPORT;
7825 7825 break;
7826 7826 default:
7827 7827 val->PortType = FC_HBA_PORTTYPE_OTHER;
7828 7828 break;
7829 7829 }
7830 7830
7831 7831
7832 7832 /*
7833 7833 * If fp has decided that the topology is public loop,
7834 7834 * we will indicate that using the appropriate
7835 7835 * FC HBA API constant.
7836 7836 */
7837 7837 switch (port->fp_topology) {
7838 7838 case FC_TOP_PUBLIC_LOOP:
7839 7839 val->PortType = FC_HBA_PORTTYPE_NLPORT;
7840 7840 break;
7841 7841
7842 7842 case FC_TOP_PT_PT:
7843 7843 val->PortType = FC_HBA_PORTTYPE_PTP;
7844 7844 break;
7845 7845
7846 7846 case FC_TOP_UNKNOWN:
7847 7847 /*
7848 7848 * This should cover the case where nothing is connected
7849 7849 * to the port. Crystal+ is p'bly an exception here.
7850 7850 * For Crystal+, port 0 will come up as private loop
7851 7851 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7852 7852 * nothing is connected to it.
7853 7853 * Current plan is to let userland handle this.
7854 7854 */
7855 7855 if (port->fp_bind_state == FC_STATE_OFFLINE) {
7856 7856 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7857 7857 }
7858 7858 break;
7859 7859
7860 7860 default:
7861 7861 /*
7862 7862 * Do Nothing.
7863 7863 * Unused:
7864 7864 * val->PortType = FC_HBA_PORTTYPE_GPORT;
7865 7865 */
7866 7866 break;
7867 7867 }
7868 7868
7869 7869 val->PortSupportedClassofService =
7870 7870 port->fp_hba_port_attrs.supported_cos;
7871 7871 val->PortSupportedFc4Types[0] = 0;
7872 7872 bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7873 7873 sizeof (val->PortActiveFc4Types));
7874 7874 bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7875 7875 port->fp_sym_port_namelen);
7876 7876 val->PortSupportedSpeed =
7877 7877 port->fp_hba_port_attrs.supported_speed;
7878 7878
7879 7879 switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7880 7880 case FC_STATE_1GBIT_SPEED:
7881 7881 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7882 7882 break;
7883 7883 case FC_STATE_2GBIT_SPEED:
7884 7884 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7885 7885 break;
7886 7886 case FC_STATE_4GBIT_SPEED:
7887 7887 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7888 7888 break;
7889 7889 case FC_STATE_8GBIT_SPEED:
7890 7890 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7891 7891 break;
7892 7892 case FC_STATE_10GBIT_SPEED:
7893 7893 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7894 7894 break;
7895 7895 case FC_STATE_16GBIT_SPEED:
7896 7896 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7897 7897 break;
7898 7898 default:
7899 7899 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7900 7900 break;
7901 7901 }
7902 7902 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7903 7903 val->NumberofDiscoveredPorts = port->fp_dev_count;
7904 7904 mutex_exit(&port->fp_mutex);
7905 7905
7906 7906 if (use32 == B_TRUE) {
7907 7907 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7908 7908 val32->version = val->version;
7909 7909 val32->lastChange = val->lastChange;
7910 7910 val32->fp_minor = val->fp_minor;
7911 7911
7912 7912 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7913 7913 sizeof (val->PortWWN.raw_wwn));
7914 7914 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7915 7915 sizeof (val->NodeWWN.raw_wwn));
7916 7916 val32->PortFcId = val->PortFcId;
7917 7917 val32->PortState = val->PortState;
7918 7918 val32->PortType = val->PortType;
7919 7919
7920 7920 val32->PortSupportedClassofService =
7921 7921 val->PortSupportedClassofService;
7922 7922 bcopy(val->PortActiveFc4Types,
7923 7923 val32->PortActiveFc4Types,
7924 7924 sizeof (val->PortActiveFc4Types));
7925 7925 bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7926 7926 sizeof (val->PortSymbolicName));
7927 7927 bcopy(&val->FabricName, &val32->FabricName,
7928 7928 sizeof (val->FabricName.raw_wwn));
7929 7929 val32->PortSupportedSpeed = val->PortSupportedSpeed;
7930 7930 val32->PortSpeed = val->PortSpeed;
7931 7931
7932 7932 val32->PortMaxFrameSize = val->PortMaxFrameSize;
7933 7933 val32->NumberofDiscoveredPorts =
7934 7934 val->NumberofDiscoveredPorts;
7935 7935
7936 7936 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7937 7937 fcio->fcio_olen, mode) == 0) {
7938 7938 if (fp_fcio_copyout(fcio, data, mode)) {
7939 7939 rval = EFAULT;
7940 7940 }
7941 7941 } else {
7942 7942 rval = EFAULT;
7943 7943 }
7944 7944
7945 7945 kmem_free(val32, sizeof (*val32));
7946 7946 } else {
7947 7947 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7948 7948 fcio->fcio_olen, mode) == 0) {
7949 7949 if (fp_fcio_copyout(fcio, data, mode)) {
7950 7950 rval = EFAULT;
7951 7951 }
7952 7952 } else {
7953 7953 rval = EFAULT;
7954 7954 }
7955 7955 }
7956 7956
7957 7957 kmem_free(val, sizeof (*val));
7958 7958 break;
7959 7959 }
7960 7960
7961 7961 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7962 7962 fc_hba_port_attributes_t *val;
7963 7963 fc_hba_port_attributes32_t *val32;
7964 7964 uint32_t index = 0;
7965 7965 fc_remote_port_t *tmp_pd;
7966 7966
7967 7967 if (use32 == B_TRUE) {
7968 7968 if (fcio->fcio_olen < sizeof (*val32) ||
7969 7969 fcio->fcio_xfer != FCIO_XFER_READ) {
7970 7970 rval = EINVAL;
7971 7971 break;
7972 7972 }
7973 7973 } else {
7974 7974 if (fcio->fcio_olen < sizeof (*val) ||
7975 7975 fcio->fcio_xfer != FCIO_XFER_READ) {
7976 7976 rval = EINVAL;
7977 7977 break;
7978 7978 }
7979 7979 }
7980 7980
7981 7981 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7982 7982 rval = EFAULT;
7983 7983 break;
7984 7984 }
7985 7985
7986 7986 if (index >= port->fp_dev_count) {
7987 7987 FP_TRACE(FP_NHEAD1(9, 0),
7988 7988 "User supplied index out of range");
7989 7989 fcio->fcio_errno = FC_OUTOFBOUNDS;
7990 7990 rval = EINVAL;
7991 7991 if (fp_fcio_copyout(fcio, data, mode)) {
7992 7992 rval = EFAULT;
7993 7993 }
7994 7994 break;
7995 7995 }
7996 7996
7997 7997 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7998 7998 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7999 7999
8000 8000 mutex_enter(&port->fp_mutex);
8001 8001 tmp_pd = fctl_lookup_pd_by_index(port, index);
8002 8002
8003 8003 if (tmp_pd == NULL) {
8004 8004 fcio->fcio_errno = FC_BADPORT;
8005 8005 rval = EINVAL;
8006 8006 } else {
8007 8007 val->lastChange = port->fp_last_change;
8008 8008 val->fp_minor = port->fp_instance;
8009 8009
8010 8010 mutex_enter(&tmp_pd->pd_mutex);
8011 8011 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8012 8012 &val->PortWWN.raw_wwn,
8013 8013 sizeof (val->PortWWN.raw_wwn));
8014 8014 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8015 8015 &val->NodeWWN.raw_wwn,
8016 8016 sizeof (val->NodeWWN.raw_wwn));
8017 8017 val->PortFcId = tmp_pd->pd_port_id.port_id;
8018 8018 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8019 8019 tmp_pd->pd_spn_len);
8020 8020 val->PortSupportedClassofService = tmp_pd->pd_cos;
8021 8021 /*
8022 8022 * we will assume the sizeof these pd_fc4types and
8023 8023 * portActiveFc4Types will remain the same. we could
8024 8024 * add in a check for it, but we decided it was unneeded
8025 8025 */
8026 8026 bcopy((caddr_t)tmp_pd->pd_fc4types,
8027 8027 val->PortActiveFc4Types,
8028 8028 sizeof (tmp_pd->pd_fc4types));
8029 8029 val->PortState =
8030 8030 fp_map_remote_port_state(tmp_pd->pd_state);
8031 8031 mutex_exit(&tmp_pd->pd_mutex);
8032 8032
8033 8033 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8034 8034 val->PortSupportedFc4Types[0] = 0;
8035 8035 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8036 8036 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8037 8037 val->PortMaxFrameSize = 0;
8038 8038 val->NumberofDiscoveredPorts = 0;
8039 8039
8040 8040 if (use32 == B_TRUE) {
8041 8041 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8042 8042 val32->version = val->version;
8043 8043 val32->lastChange = val->lastChange;
8044 8044 val32->fp_minor = val->fp_minor;
8045 8045
8046 8046 bcopy(&val->PortWWN.raw_wwn,
8047 8047 &val32->PortWWN.raw_wwn,
8048 8048 sizeof (val->PortWWN.raw_wwn));
8049 8049 bcopy(&val->NodeWWN.raw_wwn,
8050 8050 &val32->NodeWWN.raw_wwn,
8051 8051 sizeof (val->NodeWWN.raw_wwn));
8052 8052 val32->PortFcId = val->PortFcId;
8053 8053 bcopy(val->PortSymbolicName,
8054 8054 val32->PortSymbolicName,
8055 8055 sizeof (val->PortSymbolicName));
8056 8056 val32->PortSupportedClassofService =
8057 8057 val->PortSupportedClassofService;
8058 8058 bcopy(val->PortActiveFc4Types,
8059 8059 val32->PortActiveFc4Types,
8060 8060 sizeof (tmp_pd->pd_fc4types));
8061 8061
8062 8062 val32->PortType = val->PortType;
8063 8063 val32->PortState = val->PortState;
8064 8064 val32->PortSupportedFc4Types[0] =
8065 8065 val->PortSupportedFc4Types[0];
8066 8066 val32->PortSupportedSpeed =
8067 8067 val->PortSupportedSpeed;
8068 8068 val32->PortSpeed = val->PortSpeed;
8069 8069 val32->PortMaxFrameSize =
8070 8070 val->PortMaxFrameSize;
8071 8071 val32->NumberofDiscoveredPorts =
8072 8072 val->NumberofDiscoveredPorts;
8073 8073
8074 8074 if (fp_copyout((void *)val32,
8075 8075 (void *)fcio->fcio_obuf,
8076 8076 fcio->fcio_olen, mode) == 0) {
8077 8077 if (fp_fcio_copyout(fcio,
8078 8078 data, mode)) {
8079 8079 rval = EFAULT;
8080 8080 }
8081 8081 } else {
8082 8082 rval = EFAULT;
8083 8083 }
8084 8084
8085 8085 kmem_free(val32, sizeof (*val32));
8086 8086 } else {
8087 8087 if (fp_copyout((void *)val,
8088 8088 (void *)fcio->fcio_obuf,
8089 8089 fcio->fcio_olen, mode) == 0) {
8090 8090 if (fp_fcio_copyout(fcio, data, mode)) {
8091 8091 rval = EFAULT;
8092 8092 }
8093 8093 } else {
8094 8094 rval = EFAULT;
8095 8095 }
8096 8096 }
8097 8097 }
8098 8098
8099 8099 mutex_exit(&port->fp_mutex);
8100 8100 kmem_free(val, sizeof (*val));
8101 8101 break;
8102 8102 }
8103 8103
8104 8104 case FCIO_GET_PORT_ATTRIBUTES: {
8105 8105 fc_hba_port_attributes_t *val;
8106 8106 fc_hba_port_attributes32_t *val32;
8107 8107 la_wwn_t wwn;
8108 8108 fc_remote_port_t *tmp_pd;
8109 8109
8110 8110 if (use32 == B_TRUE) {
8111 8111 if (fcio->fcio_olen < sizeof (*val32) ||
8112 8112 fcio->fcio_xfer != FCIO_XFER_READ) {
8113 8113 rval = EINVAL;
8114 8114 break;
8115 8115 }
8116 8116 } else {
8117 8117 if (fcio->fcio_olen < sizeof (*val) ||
8118 8118 fcio->fcio_xfer != FCIO_XFER_READ) {
8119 8119 rval = EINVAL;
8120 8120 break;
8121 8121 }
8122 8122 }
8123 8123
8124 8124 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8125 8125 rval = EFAULT;
8126 8126 break;
8127 8127 }
8128 8128
8129 8129 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8130 8130 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8131 8131
8132 8132 mutex_enter(&port->fp_mutex);
8133 8133 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8134 8134 val->lastChange = port->fp_last_change;
8135 8135 val->fp_minor = port->fp_instance;
8136 8136 mutex_exit(&port->fp_mutex);
8137 8137
8138 8138 if (tmp_pd == NULL) {
8139 8139 fcio->fcio_errno = FC_BADWWN;
8140 8140 rval = EINVAL;
8141 8141 } else {
8142 8142 mutex_enter(&tmp_pd->pd_mutex);
8143 8143 bcopy(&tmp_pd->pd_port_name.raw_wwn,
8144 8144 &val->PortWWN.raw_wwn,
8145 8145 sizeof (val->PortWWN.raw_wwn));
8146 8146 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8147 8147 &val->NodeWWN.raw_wwn,
8148 8148 sizeof (val->NodeWWN.raw_wwn));
8149 8149 val->PortFcId = tmp_pd->pd_port_id.port_id;
8150 8150 bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8151 8151 tmp_pd->pd_spn_len);
8152 8152 val->PortSupportedClassofService = tmp_pd->pd_cos;
8153 8153 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8154 8154 val->PortState =
8155 8155 fp_map_remote_port_state(tmp_pd->pd_state);
8156 8156 val->PortSupportedFc4Types[0] = 0;
8157 8157 /*
8158 8158 * we will assume the sizeof these pd_fc4types and
8159 8159 * portActiveFc4Types will remain the same. we could
8160 8160 * add in a check for it, but we decided it was unneeded
8161 8161 */
8162 8162 bcopy((caddr_t)tmp_pd->pd_fc4types,
8163 8163 val->PortActiveFc4Types,
8164 8164 sizeof (tmp_pd->pd_fc4types));
8165 8165 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8166 8166 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8167 8167 val->PortMaxFrameSize = 0;
8168 8168 val->NumberofDiscoveredPorts = 0;
8169 8169 mutex_exit(&tmp_pd->pd_mutex);
8170 8170
8171 8171 if (use32 == B_TRUE) {
8172 8172 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8173 8173 val32->version = val->version;
8174 8174 val32->lastChange = val->lastChange;
8175 8175 val32->fp_minor = val->fp_minor;
8176 8176 bcopy(&val->PortWWN.raw_wwn,
8177 8177 &val32->PortWWN.raw_wwn,
8178 8178 sizeof (val->PortWWN.raw_wwn));
8179 8179 bcopy(&val->NodeWWN.raw_wwn,
8180 8180 &val32->NodeWWN.raw_wwn,
8181 8181 sizeof (val->NodeWWN.raw_wwn));
8182 8182 val32->PortFcId = val->PortFcId;
8183 8183 bcopy(val->PortSymbolicName,
8184 8184 val32->PortSymbolicName,
8185 8185 sizeof (val->PortSymbolicName));
8186 8186 val32->PortSupportedClassofService =
8187 8187 val->PortSupportedClassofService;
8188 8188 val32->PortType = val->PortType;
8189 8189 val32->PortState = val->PortState;
8190 8190 val32->PortSupportedFc4Types[0] =
8191 8191 val->PortSupportedFc4Types[0];
8192 8192 bcopy(val->PortActiveFc4Types,
8193 8193 val32->PortActiveFc4Types,
8194 8194 sizeof (tmp_pd->pd_fc4types));
8195 8195 val32->PortSupportedSpeed =
8196 8196 val->PortSupportedSpeed;
8197 8197 val32->PortSpeed = val->PortSpeed;
8198 8198 val32->PortMaxFrameSize = val->PortMaxFrameSize;
8199 8199 val32->NumberofDiscoveredPorts =
8200 8200 val->NumberofDiscoveredPorts;
8201 8201
8202 8202 if (fp_copyout((void *)val32,
8203 8203 (void *)fcio->fcio_obuf,
8204 8204 fcio->fcio_olen, mode) == 0) {
8205 8205 if (fp_fcio_copyout(fcio, data, mode)) {
8206 8206 rval = EFAULT;
8207 8207 }
8208 8208 } else {
8209 8209 rval = EFAULT;
8210 8210 }
8211 8211
8212 8212 kmem_free(val32, sizeof (*val32));
8213 8213 } else {
8214 8214 if (fp_copyout((void *)val,
8215 8215 (void *)fcio->fcio_obuf,
8216 8216 fcio->fcio_olen, mode) == 0) {
8217 8217 if (fp_fcio_copyout(fcio, data, mode)) {
8218 8218 rval = EFAULT;
8219 8219 }
8220 8220 } else {
8221 8221 rval = EFAULT;
8222 8222 }
8223 8223 }
8224 8224 }
8225 8225 kmem_free(val, sizeof (*val));
8226 8226 break;
8227 8227 }
8228 8228
8229 8229 case FCIO_GET_NUM_DEVS: {
8230 8230 int num_devices;
8231 8231
8232 8232 if (fcio->fcio_olen != sizeof (num_devices) ||
8233 8233 fcio->fcio_xfer != FCIO_XFER_READ) {
8234 8234 rval = EINVAL;
8235 8235 break;
8236 8236 }
8237 8237
8238 8238 mutex_enter(&port->fp_mutex);
8239 8239 switch (port->fp_topology) {
8240 8240 case FC_TOP_PRIVATE_LOOP:
8241 8241 case FC_TOP_PT_PT:
8242 8242 num_devices = port->fp_total_devices;
8243 8243 fcio->fcio_errno = FC_SUCCESS;
8244 8244 break;
8245 8245
8246 8246 case FC_TOP_PUBLIC_LOOP:
8247 8247 case FC_TOP_FABRIC:
8248 8248 mutex_exit(&port->fp_mutex);
8249 8249 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8250 8250 NULL, KM_SLEEP);
8251 8251 ASSERT(job != NULL);
8252 8252
8253 8253 /*
8254 8254 * In FC-GS-2 the Name Server doesn't send out
8255 8255 * RSCNs for any Name Server Database updates
8256 8256 * When it is finally fixed there is no need
8257 8257 * to probe as below and should be removed.
8258 8258 */
8259 8259 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8260 8260 fctl_dealloc_job(job);
8261 8261
8262 8262 mutex_enter(&port->fp_mutex);
8263 8263 num_devices = port->fp_total_devices;
8264 8264 fcio->fcio_errno = FC_SUCCESS;
8265 8265 break;
8266 8266
8267 8267 case FC_TOP_NO_NS:
8268 8268 /* FALLTHROUGH */
8269 8269 case FC_TOP_UNKNOWN:
8270 8270 /* FALLTHROUGH */
8271 8271 default:
8272 8272 num_devices = 0;
8273 8273 fcio->fcio_errno = FC_SUCCESS;
8274 8274 break;
8275 8275 }
8276 8276 mutex_exit(&port->fp_mutex);
8277 8277
8278 8278 if (fp_copyout((void *)&num_devices,
8279 8279 (void *)fcio->fcio_obuf, fcio->fcio_olen,
8280 8280 mode) == 0) {
8281 8281 if (fp_fcio_copyout(fcio, data, mode)) {
8282 8282 rval = EFAULT;
8283 8283 }
8284 8284 } else {
8285 8285 rval = EFAULT;
8286 8286 }
8287 8287 break;
8288 8288 }
8289 8289
8290 8290 case FCIO_GET_DEV_LIST: {
8291 8291 int num_devices;
8292 8292 int new_count;
8293 8293 int map_size;
8294 8294
8295 8295 if (fcio->fcio_xfer != FCIO_XFER_READ ||
8296 8296 fcio->fcio_alen != sizeof (new_count)) {
8297 8297 rval = EINVAL;
8298 8298 break;
8299 8299 }
8300 8300
8301 8301 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8302 8302
8303 8303 mutex_enter(&port->fp_mutex);
8304 8304 if (num_devices < port->fp_total_devices) {
8305 8305 fcio->fcio_errno = FC_TOOMANY;
8306 8306 new_count = port->fp_total_devices;
8307 8307 mutex_exit(&port->fp_mutex);
8308 8308
8309 8309 if (fp_copyout((void *)&new_count,
8310 8310 (void *)fcio->fcio_abuf,
8311 8311 sizeof (new_count), mode)) {
8312 8312 rval = EFAULT;
8313 8313 break;
8314 8314 }
8315 8315
8316 8316 if (fp_fcio_copyout(fcio, data, mode)) {
8317 8317 rval = EFAULT;
8318 8318 break;
8319 8319 }
8320 8320 rval = EINVAL;
8321 8321 break;
8322 8322 }
8323 8323
8324 8324 if (port->fp_total_devices <= 0) {
8325 8325 fcio->fcio_errno = FC_NO_MAP;
8326 8326 new_count = port->fp_total_devices;
8327 8327 mutex_exit(&port->fp_mutex);
8328 8328
8329 8329 if (fp_copyout((void *)&new_count,
8330 8330 (void *)fcio->fcio_abuf,
8331 8331 sizeof (new_count), mode)) {
8332 8332 rval = EFAULT;
8333 8333 break;
8334 8334 }
8335 8335
8336 8336 if (fp_fcio_copyout(fcio, data, mode)) {
8337 8337 rval = EFAULT;
8338 8338 break;
8339 8339 }
8340 8340 rval = EINVAL;
8341 8341 break;
8342 8342 }
8343 8343
8344 8344 switch (port->fp_topology) {
8345 8345 case FC_TOP_PRIVATE_LOOP:
8346 8346 if (fp_fillout_loopmap(port, fcio,
8347 8347 mode) != FC_SUCCESS) {
8348 8348 rval = EFAULT;
8349 8349 break;
8350 8350 }
8351 8351 if (fp_fcio_copyout(fcio, data, mode)) {
8352 8352 rval = EFAULT;
8353 8353 }
8354 8354 break;
8355 8355
8356 8356 case FC_TOP_PT_PT:
8357 8357 if (fp_fillout_p2pmap(port, fcio,
8358 8358 mode) != FC_SUCCESS) {
8359 8359 rval = EFAULT;
8360 8360 break;
8361 8361 }
8362 8362 if (fp_fcio_copyout(fcio, data, mode)) {
8363 8363 rval = EFAULT;
8364 8364 }
8365 8365 break;
8366 8366
8367 8367 case FC_TOP_PUBLIC_LOOP:
8368 8368 case FC_TOP_FABRIC: {
8369 8369 fctl_ns_req_t *ns_cmd;
8370 8370
8371 8371 map_size =
8372 8372 sizeof (fc_port_dev_t) * port->fp_total_devices;
8373 8373
8374 8374 mutex_exit(&port->fp_mutex);
8375 8375
8376 8376 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8377 8377 sizeof (ns_resp_gan_t), map_size,
8378 8378 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8379 8379 KM_SLEEP);
8380 8380 ASSERT(ns_cmd != NULL);
8381 8381
8382 8382 ns_cmd->ns_gan_index = 0;
8383 8383 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8384 8384 ns_cmd->ns_cmd_code = NS_GA_NXT;
8385 8385 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8386 8386
8387 8387 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8388 8388 NULL, KM_SLEEP);
8389 8389 ASSERT(job != NULL);
8390 8390
8391 8391 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8392 8392
8393 8393 if (ret != FC_SUCCESS ||
8394 8394 job->job_result != FC_SUCCESS) {
8395 8395 fctl_free_ns_cmd(ns_cmd);
8396 8396
8397 8397 fcio->fcio_errno = job->job_result;
8398 8398 new_count = 0;
8399 8399 if (fp_copyout((void *)&new_count,
8400 8400 (void *)fcio->fcio_abuf,
8401 8401 sizeof (new_count), mode)) {
8402 8402 fctl_dealloc_job(job);
8403 8403 mutex_enter(&port->fp_mutex);
8404 8404 rval = EFAULT;
8405 8405 break;
8406 8406 }
8407 8407
8408 8408 if (fp_fcio_copyout(fcio, data, mode)) {
8409 8409 fctl_dealloc_job(job);
8410 8410 mutex_enter(&port->fp_mutex);
8411 8411 rval = EFAULT;
8412 8412 break;
8413 8413 }
8414 8414 rval = EIO;
8415 8415 mutex_enter(&port->fp_mutex);
8416 8416 break;
8417 8417 }
8418 8418 fctl_dealloc_job(job);
8419 8419
8420 8420 new_count = ns_cmd->ns_gan_index;
8421 8421 if (fp_copyout((void *)&new_count,
8422 8422 (void *)fcio->fcio_abuf, sizeof (new_count),
8423 8423 mode)) {
8424 8424 rval = EFAULT;
8425 8425 fctl_free_ns_cmd(ns_cmd);
8426 8426 mutex_enter(&port->fp_mutex);
8427 8427 break;
8428 8428 }
8429 8429
8430 8430 if (fp_copyout((void *)ns_cmd->ns_data_buf,
8431 8431 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8432 8432 ns_cmd->ns_gan_index, mode)) {
8433 8433 rval = EFAULT;
8434 8434 fctl_free_ns_cmd(ns_cmd);
8435 8435 mutex_enter(&port->fp_mutex);
8436 8436 break;
8437 8437 }
8438 8438 fctl_free_ns_cmd(ns_cmd);
8439 8439
8440 8440 if (fp_fcio_copyout(fcio, data, mode)) {
8441 8441 rval = EFAULT;
8442 8442 }
8443 8443 mutex_enter(&port->fp_mutex);
8444 8444 break;
8445 8445 }
8446 8446
8447 8447 case FC_TOP_NO_NS:
8448 8448 /* FALLTHROUGH */
8449 8449 case FC_TOP_UNKNOWN:
8450 8450 /* FALLTHROUGH */
8451 8451 default:
8452 8452 fcio->fcio_errno = FC_NO_MAP;
8453 8453 num_devices = port->fp_total_devices;
8454 8454
8455 8455 if (fp_copyout((void *)&new_count,
8456 8456 (void *)fcio->fcio_abuf,
8457 8457 sizeof (new_count), mode)) {
8458 8458 rval = EFAULT;
8459 8459 break;
8460 8460 }
8461 8461
8462 8462 if (fp_fcio_copyout(fcio, data, mode)) {
8463 8463 rval = EFAULT;
8464 8464 break;
8465 8465 }
8466 8466 rval = EINVAL;
8467 8467 break;
8468 8468 }
8469 8469 mutex_exit(&port->fp_mutex);
8470 8470 break;
8471 8471 }
8472 8472
8473 8473 case FCIO_GET_SYM_PNAME: {
8474 8474 rval = ENOTSUP;
8475 8475 break;
8476 8476 }
8477 8477
8478 8478 case FCIO_GET_SYM_NNAME: {
8479 8479 rval = ENOTSUP;
8480 8480 break;
8481 8481 }
8482 8482
8483 8483 case FCIO_SET_SYM_PNAME: {
8484 8484 rval = ENOTSUP;
8485 8485 break;
8486 8486 }
8487 8487
8488 8488 case FCIO_SET_SYM_NNAME: {
8489 8489 rval = ENOTSUP;
8490 8490 break;
8491 8491 }
8492 8492
8493 8493 case FCIO_GET_LOGI_PARAMS: {
8494 8494 la_wwn_t pwwn;
8495 8495 la_wwn_t *my_pwwn;
8496 8496 la_els_logi_t *params;
8497 8497 la_els_logi32_t *params32;
8498 8498 fc_remote_node_t *node;
8499 8499 fc_remote_port_t *pd;
8500 8500
8501 8501 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8502 8502 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8503 8503 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8504 8504 rval = EINVAL;
8505 8505 break;
8506 8506 }
8507 8507
8508 8508 if (use32 == B_TRUE) {
8509 8509 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8510 8510 rval = EINVAL;
8511 8511 break;
8512 8512 }
8513 8513 } else {
8514 8514 if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8515 8515 rval = EINVAL;
8516 8516 break;
8517 8517 }
8518 8518 }
8519 8519
8520 8520 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8521 8521 rval = EFAULT;
8522 8522 break;
8523 8523 }
8524 8524
8525 8525 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8526 8526 if (pd == NULL) {
8527 8527 mutex_enter(&port->fp_mutex);
8528 8528 my_pwwn = &port->fp_service_params.nport_ww_name;
8529 8529 mutex_exit(&port->fp_mutex);
8530 8530
8531 8531 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8532 8532 rval = ENXIO;
8533 8533 break;
8534 8534 }
8535 8535
8536 8536 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8537 8537 mutex_enter(&port->fp_mutex);
8538 8538 *params = port->fp_service_params;
8539 8539 mutex_exit(&port->fp_mutex);
8540 8540 } else {
8541 8541 params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8542 8542
8543 8543 mutex_enter(&pd->pd_mutex);
8544 8544 params->ls_code.mbz = params->ls_code.ls_code = 0;
8545 8545 params->common_service = pd->pd_csp;
8546 8546 params->nport_ww_name = pd->pd_port_name;
8547 8547 params->class_1 = pd->pd_clsp1;
8548 8548 params->class_2 = pd->pd_clsp2;
8549 8549 params->class_3 = pd->pd_clsp3;
8550 8550 node = pd->pd_remote_nodep;
8551 8551 mutex_exit(&pd->pd_mutex);
8552 8552
8553 8553 bzero(params->reserved, sizeof (params->reserved));
8554 8554
8555 8555 mutex_enter(&node->fd_mutex);
8556 8556 bcopy(node->fd_vv, params->vendor_version,
8557 8557 sizeof (node->fd_vv));
8558 8558 params->node_ww_name = node->fd_node_name;
8559 8559 mutex_exit(&node->fd_mutex);
8560 8560
8561 8561 fctl_release_remote_port(pd);
8562 8562 }
8563 8563
8564 8564 if (use32 == B_TRUE) {
8565 8565 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8566 8566
8567 8567 params32->ls_code.mbz = params->ls_code.mbz;
8568 8568 params32->common_service = params->common_service;
8569 8569 params32->nport_ww_name = params->nport_ww_name;
8570 8570 params32->class_1 = params->class_1;
8571 8571 params32->class_2 = params->class_2;
8572 8572 params32->class_3 = params->class_3;
8573 8573 bzero(params32->reserved, sizeof (params32->reserved));
8574 8574 bcopy(params->vendor_version, params32->vendor_version,
8575 8575 sizeof (node->fd_vv));
8576 8576 params32->node_ww_name = params->node_ww_name;
8577 8577
8578 8578 if (ddi_copyout((void *)params32,
8579 8579 (void *)fcio->fcio_obuf,
8580 8580 sizeof (*params32), mode)) {
8581 8581 rval = EFAULT;
8582 8582 }
8583 8583
8584 8584 kmem_free(params32, sizeof (*params32));
8585 8585 } else {
8586 8586 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8587 8587 sizeof (*params), mode)) {
8588 8588 rval = EFAULT;
8589 8589 }
8590 8590 }
8591 8591
8592 8592 kmem_free(params, sizeof (*params));
8593 8593 if (fp_fcio_copyout(fcio, data, mode)) {
8594 8594 rval = EFAULT;
8595 8595 }
8596 8596 break;
8597 8597 }
8598 8598
8599 8599 case FCIO_DEV_LOGOUT:
8600 8600 case FCIO_DEV_LOGIN:
8601 8601 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8602 8602 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8603 8603 rval = EINVAL;
8604 8604
8605 8605 if (fp_fcio_copyout(fcio, data, mode)) {
8606 8606 rval = EFAULT;
8607 8607 }
8608 8608 break;
8609 8609 }
8610 8610
8611 8611 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8612 8612 jcode = JOB_FCIO_LOGIN;
8613 8613 } else {
8614 8614 jcode = JOB_FCIO_LOGOUT;
8615 8615 }
8616 8616
8617 8617 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8618 8618 bcopy(fcio, kfcio, sizeof (*fcio));
8619 8619
8620 8620 if (kfcio->fcio_ilen) {
8621 8621 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8622 8622 KM_SLEEP);
8623 8623
8624 8624 if (ddi_copyin((void *)fcio->fcio_ibuf,
8625 8625 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8626 8626 mode)) {
8627 8627 rval = EFAULT;
8628 8628
8629 8629 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8630 8630 kmem_free(kfcio, sizeof (*kfcio));
8631 8631 fcio->fcio_errno = job->job_result;
8632 8632 if (fp_fcio_copyout(fcio, data, mode)) {
8633 8633 rval = EFAULT;
8634 8634 }
8635 8635 break;
8636 8636 }
8637 8637 }
8638 8638
8639 8639 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8640 8640 job->job_private = kfcio;
8641 8641
8642 8642 fctl_enque_job(port, job);
8643 8643 fctl_jobwait(job);
8644 8644
8645 8645 rval = job->job_result;
8646 8646
8647 8647 fcio->fcio_errno = kfcio->fcio_errno;
8648 8648 if (fp_fcio_copyout(fcio, data, mode)) {
8649 8649 rval = EFAULT;
8650 8650 }
8651 8651
8652 8652 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8653 8653 kmem_free(kfcio, sizeof (*kfcio));
8654 8654 fctl_dealloc_job(job);
8655 8655 break;
8656 8656
8657 8657 case FCIO_GET_STATE: {
8658 8658 la_wwn_t pwwn;
8659 8659 uint32_t state;
8660 8660 fc_remote_port_t *pd;
8661 8661 fctl_ns_req_t *ns_cmd;
8662 8662
8663 8663 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8664 8664 fcio->fcio_olen != sizeof (state) ||
8665 8665 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8666 8666 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8667 8667 rval = EINVAL;
8668 8668 break;
8669 8669 }
8670 8670
8671 8671 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8672 8672 rval = EFAULT;
8673 8673 break;
8674 8674 }
8675 8675 fcio->fcio_errno = 0;
8676 8676
8677 8677 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8678 8678 if (pd == NULL) {
8679 8679 mutex_enter(&port->fp_mutex);
8680 8680 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8681 8681 mutex_exit(&port->fp_mutex);
8682 8682 job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8683 8683 NULL, NULL, KM_SLEEP);
8684 8684
8685 8685 job->job_counter = 1;
8686 8686 job->job_result = FC_SUCCESS;
8687 8687
8688 8688 ns_cmd = fctl_alloc_ns_cmd(
8689 8689 sizeof (ns_req_gid_pn_t),
8690 8690 sizeof (ns_resp_gid_pn_t),
8691 8691 sizeof (ns_resp_gid_pn_t),
8692 8692 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8693 8693 ASSERT(ns_cmd != NULL);
8694 8694
8695 8695 ns_cmd->ns_cmd_code = NS_GID_PN;
8696 8696 ((ns_req_gid_pn_t *)
8697 8697 (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8698 8698
8699 8699 ret = fp_ns_query(port, ns_cmd, job,
8700 8700 1, KM_SLEEP);
8701 8701
8702 8702 if (ret != FC_SUCCESS || job->job_result !=
8703 8703 FC_SUCCESS) {
8704 8704 if (ret != FC_SUCCESS) {
8705 8705 fcio->fcio_errno = ret;
8706 8706 } else {
8707 8707 fcio->fcio_errno =
8708 8708 job->job_result;
8709 8709 }
8710 8710 rval = EIO;
8711 8711 } else {
8712 8712 state = PORT_DEVICE_INVALID;
8713 8713 }
8714 8714 fctl_free_ns_cmd(ns_cmd);
8715 8715 fctl_dealloc_job(job);
8716 8716 } else {
8717 8717 mutex_exit(&port->fp_mutex);
8718 8718 fcio->fcio_errno = FC_BADWWN;
8719 8719 rval = ENXIO;
8720 8720 }
8721 8721 } else {
8722 8722 mutex_enter(&pd->pd_mutex);
8723 8723 state = pd->pd_state;
8724 8724 mutex_exit(&pd->pd_mutex);
8725 8725
8726 8726 fctl_release_remote_port(pd);
8727 8727 }
8728 8728
8729 8729 if (!rval) {
8730 8730 if (ddi_copyout((void *)&state,
8731 8731 (void *)fcio->fcio_obuf, sizeof (state),
8732 8732 mode)) {
8733 8733 rval = EFAULT;
8734 8734 }
8735 8735 }
8736 8736 if (fp_fcio_copyout(fcio, data, mode)) {
8737 8737 rval = EFAULT;
8738 8738 }
8739 8739 break;
8740 8740 }
8741 8741
8742 8742 case FCIO_DEV_REMOVE: {
8743 8743 la_wwn_t pwwn;
8744 8744 fc_portmap_t *changelist;
8745 8745 fc_remote_port_t *pd;
8746 8746
8747 8747 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8748 8748 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8749 8749 rval = EINVAL;
8750 8750 break;
8751 8751 }
8752 8752
8753 8753 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8754 8754 rval = EFAULT;
8755 8755 break;
8756 8756 }
8757 8757
8758 8758 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8759 8759 if (pd == NULL) {
8760 8760 rval = ENXIO;
8761 8761 fcio->fcio_errno = FC_BADWWN;
8762 8762 if (fp_fcio_copyout(fcio, data, mode)) {
8763 8763 rval = EFAULT;
8764 8764 }
8765 8765 break;
8766 8766 }
8767 8767
8768 8768 mutex_enter(&pd->pd_mutex);
8769 8769 if (pd->pd_ref_count > 1) {
8770 8770 mutex_exit(&pd->pd_mutex);
8771 8771
8772 8772 rval = EBUSY;
8773 8773 fcio->fcio_errno = FC_FAILURE;
8774 8774 fctl_release_remote_port(pd);
8775 8775
8776 8776 if (fp_fcio_copyout(fcio, data, mode)) {
8777 8777 rval = EFAULT;
8778 8778 }
8779 8779 break;
8780 8780 }
8781 8781 mutex_exit(&pd->pd_mutex);
8782 8782
8783 8783 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8784 8784
8785 8785 fctl_copy_portmap(changelist, pd);
8786 8786 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8787 8787 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8788 8788
8789 8789 fctl_release_remote_port(pd);
8790 8790 break;
8791 8791 }
8792 8792
8793 8793 case FCIO_GET_FCODE_REV: {
8794 8794 caddr_t fcode_rev;
8795 8795 fc_fca_pm_t pm;
8796 8796
8797 8797 if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8798 8798 fcio->fcio_xfer != FCIO_XFER_READ) {
8799 8799 rval = EINVAL;
8800 8800 break;
8801 8801 }
8802 8802 bzero((caddr_t)&pm, sizeof (pm));
8803 8803
8804 8804 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8805 8805
8806 8806 pm.pm_cmd_flags = FC_FCA_PM_READ;
8807 8807 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8808 8808 pm.pm_data_len = fcio->fcio_olen;
8809 8809 pm.pm_data_buf = fcode_rev;
8810 8810
8811 8811 ret = port->fp_fca_tran->fca_port_manage(
8812 8812 port->fp_fca_handle, &pm);
8813 8813
8814 8814 if (ret == FC_SUCCESS) {
8815 8815 if (ddi_copyout((void *)fcode_rev,
8816 8816 (void *)fcio->fcio_obuf,
8817 8817 fcio->fcio_olen, mode) == 0) {
8818 8818 if (fp_fcio_copyout(fcio, data, mode)) {
8819 8819 rval = EFAULT;
8820 8820 }
8821 8821 } else {
8822 8822 rval = EFAULT;
8823 8823 }
8824 8824 } else {
8825 8825 /*
8826 8826 * check if buffer was not large enough to obtain
8827 8827 * FCODE version.
8828 8828 */
8829 8829 if (pm.pm_data_len > fcio->fcio_olen) {
8830 8830 rval = ENOMEM;
8831 8831 } else {
8832 8832 rval = EIO;
8833 8833 }
8834 8834 fcio->fcio_errno = ret;
8835 8835 if (fp_fcio_copyout(fcio, data, mode)) {
8836 8836 rval = EFAULT;
8837 8837 }
8838 8838 }
8839 8839 kmem_free(fcode_rev, fcio->fcio_olen);
8840 8840 break;
8841 8841 }
8842 8842
8843 8843 case FCIO_GET_FW_REV: {
8844 8844 caddr_t fw_rev;
8845 8845 fc_fca_pm_t pm;
8846 8846
8847 8847 if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8848 8848 fcio->fcio_xfer != FCIO_XFER_READ) {
8849 8849 rval = EINVAL;
8850 8850 break;
8851 8851 }
8852 8852 bzero((caddr_t)&pm, sizeof (pm));
8853 8853
8854 8854 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8855 8855
8856 8856 pm.pm_cmd_flags = FC_FCA_PM_READ;
8857 8857 pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8858 8858 pm.pm_data_len = fcio->fcio_olen;
8859 8859 pm.pm_data_buf = fw_rev;
8860 8860
8861 8861 ret = port->fp_fca_tran->fca_port_manage(
8862 8862 port->fp_fca_handle, &pm);
8863 8863
8864 8864 if (ret == FC_SUCCESS) {
8865 8865 if (ddi_copyout((void *)fw_rev,
8866 8866 (void *)fcio->fcio_obuf,
8867 8867 fcio->fcio_olen, mode) == 0) {
8868 8868 if (fp_fcio_copyout(fcio, data, mode)) {
8869 8869 rval = EFAULT;
8870 8870 }
8871 8871 } else {
8872 8872 rval = EFAULT;
8873 8873 }
8874 8874 } else {
8875 8875 if (fp_fcio_copyout(fcio, data, mode)) {
8876 8876 rval = EFAULT;
8877 8877 }
8878 8878 rval = EIO;
8879 8879 }
8880 8880 kmem_free(fw_rev, fcio->fcio_olen);
8881 8881 break;
8882 8882 }
8883 8883
8884 8884 case FCIO_GET_DUMP_SIZE: {
8885 8885 uint32_t dump_size;
8886 8886 fc_fca_pm_t pm;
8887 8887
8888 8888 if (fcio->fcio_olen != sizeof (dump_size) ||
8889 8889 fcio->fcio_xfer != FCIO_XFER_READ) {
8890 8890 rval = EINVAL;
8891 8891 break;
8892 8892 }
8893 8893 bzero((caddr_t)&pm, sizeof (pm));
8894 8894 pm.pm_cmd_flags = FC_FCA_PM_READ;
8895 8895 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8896 8896 pm.pm_data_len = sizeof (dump_size);
8897 8897 pm.pm_data_buf = (caddr_t)&dump_size;
8898 8898
8899 8899 ret = port->fp_fca_tran->fca_port_manage(
8900 8900 port->fp_fca_handle, &pm);
8901 8901
8902 8902 if (ret == FC_SUCCESS) {
8903 8903 if (ddi_copyout((void *)&dump_size,
8904 8904 (void *)fcio->fcio_obuf, sizeof (dump_size),
8905 8905 mode) == 0) {
8906 8906 if (fp_fcio_copyout(fcio, data, mode)) {
8907 8907 rval = EFAULT;
8908 8908 }
8909 8909 } else {
8910 8910 rval = EFAULT;
8911 8911 }
8912 8912 } else {
8913 8913 fcio->fcio_errno = ret;
8914 8914 rval = EIO;
8915 8915 if (fp_fcio_copyout(fcio, data, mode)) {
8916 8916 rval = EFAULT;
8917 8917 }
8918 8918 }
8919 8919 break;
8920 8920 }
8921 8921
8922 8922 case FCIO_DOWNLOAD_FW: {
8923 8923 caddr_t firmware;
8924 8924 fc_fca_pm_t pm;
8925 8925
8926 8926 if (fcio->fcio_ilen <= 0 ||
8927 8927 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8928 8928 rval = EINVAL;
8929 8929 break;
8930 8930 }
8931 8931
8932 8932 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8933 8933 if (ddi_copyin(fcio->fcio_ibuf, firmware,
8934 8934 fcio->fcio_ilen, mode)) {
8935 8935 rval = EFAULT;
8936 8936 kmem_free(firmware, fcio->fcio_ilen);
8937 8937 break;
8938 8938 }
8939 8939
8940 8940 bzero((caddr_t)&pm, sizeof (pm));
8941 8941 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8942 8942 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8943 8943 pm.pm_data_len = fcio->fcio_ilen;
8944 8944 pm.pm_data_buf = firmware;
8945 8945
8946 8946 ret = port->fp_fca_tran->fca_port_manage(
8947 8947 port->fp_fca_handle, &pm);
8948 8948
8949 8949 kmem_free(firmware, fcio->fcio_ilen);
8950 8950
8951 8951 if (ret != FC_SUCCESS) {
8952 8952 fcio->fcio_errno = ret;
8953 8953 rval = EIO;
8954 8954 if (fp_fcio_copyout(fcio, data, mode)) {
8955 8955 rval = EFAULT;
8956 8956 }
8957 8957 }
8958 8958 break;
8959 8959 }
8960 8960
8961 8961 case FCIO_DOWNLOAD_FCODE: {
8962 8962 caddr_t fcode;
8963 8963 fc_fca_pm_t pm;
8964 8964
8965 8965 if (fcio->fcio_ilen <= 0 ||
8966 8966 fcio->fcio_xfer != FCIO_XFER_WRITE) {
8967 8967 rval = EINVAL;
8968 8968 break;
8969 8969 }
8970 8970
8971 8971 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8972 8972 if (ddi_copyin(fcio->fcio_ibuf, fcode,
8973 8973 fcio->fcio_ilen, mode)) {
8974 8974 rval = EFAULT;
8975 8975 kmem_free(fcode, fcio->fcio_ilen);
8976 8976 break;
8977 8977 }
8978 8978
8979 8979 bzero((caddr_t)&pm, sizeof (pm));
8980 8980 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8981 8981 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8982 8982 pm.pm_data_len = fcio->fcio_ilen;
8983 8983 pm.pm_data_buf = fcode;
8984 8984
8985 8985 ret = port->fp_fca_tran->fca_port_manage(
8986 8986 port->fp_fca_handle, &pm);
8987 8987
8988 8988 kmem_free(fcode, fcio->fcio_ilen);
8989 8989
8990 8990 if (ret != FC_SUCCESS) {
8991 8991 fcio->fcio_errno = ret;
8992 8992 rval = EIO;
8993 8993 if (fp_fcio_copyout(fcio, data, mode)) {
8994 8994 rval = EFAULT;
8995 8995 }
8996 8996 }
8997 8997 break;
8998 8998 }
8999 8999
9000 9000 case FCIO_FORCE_DUMP:
9001 9001 ret = port->fp_fca_tran->fca_reset(
9002 9002 port->fp_fca_handle, FC_FCA_CORE);
9003 9003
9004 9004 if (ret != FC_SUCCESS) {
9005 9005 fcio->fcio_errno = ret;
9006 9006 rval = EIO;
9007 9007 if (fp_fcio_copyout(fcio, data, mode)) {
9008 9008 rval = EFAULT;
9009 9009 }
9010 9010 }
9011 9011 break;
9012 9012
9013 9013 case FCIO_GET_DUMP: {
9014 9014 caddr_t dump;
9015 9015 uint32_t dump_size;
9016 9016 fc_fca_pm_t pm;
9017 9017
9018 9018 if (fcio->fcio_xfer != FCIO_XFER_READ) {
9019 9019 rval = EINVAL;
9020 9020 break;
9021 9021 }
9022 9022 bzero((caddr_t)&pm, sizeof (pm));
9023 9023
9024 9024 pm.pm_cmd_flags = FC_FCA_PM_READ;
9025 9025 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
9026 9026 pm.pm_data_len = sizeof (dump_size);
9027 9027 pm.pm_data_buf = (caddr_t)&dump_size;
9028 9028
9029 9029 ret = port->fp_fca_tran->fca_port_manage(
9030 9030 port->fp_fca_handle, &pm);
9031 9031
9032 9032 if (ret != FC_SUCCESS) {
9033 9033 fcio->fcio_errno = ret;
9034 9034 rval = EIO;
9035 9035 if (fp_fcio_copyout(fcio, data, mode)) {
9036 9036 rval = EFAULT;
9037 9037 }
9038 9038 break;
9039 9039 }
9040 9040 if (fcio->fcio_olen != dump_size) {
9041 9041 fcio->fcio_errno = FC_NOMEM;
9042 9042 rval = EINVAL;
9043 9043 if (fp_fcio_copyout(fcio, data, mode)) {
9044 9044 rval = EFAULT;
9045 9045 }
9046 9046 break;
9047 9047 }
9048 9048
9049 9049 dump = kmem_zalloc(dump_size, KM_SLEEP);
9050 9050
9051 9051 bzero((caddr_t)&pm, sizeof (pm));
9052 9052 pm.pm_cmd_flags = FC_FCA_PM_READ;
9053 9053 pm.pm_cmd_code = FC_PORT_GET_DUMP;
9054 9054 pm.pm_data_len = dump_size;
9055 9055 pm.pm_data_buf = dump;
9056 9056
9057 9057 ret = port->fp_fca_tran->fca_port_manage(
9058 9058 port->fp_fca_handle, &pm);
9059 9059
9060 9060 if (ret == FC_SUCCESS) {
9061 9061 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
9062 9062 dump_size, mode) == 0) {
9063 9063 if (fp_fcio_copyout(fcio, data, mode)) {
9064 9064 rval = EFAULT;
9065 9065 }
9066 9066 } else {
9067 9067 rval = EFAULT;
9068 9068 }
9069 9069 } else {
9070 9070 fcio->fcio_errno = ret;
9071 9071 rval = EIO;
9072 9072 if (fp_fcio_copyout(fcio, data, mode)) {
9073 9073 rval = EFAULT;
9074 9074 }
9075 9075 }
9076 9076 kmem_free(dump, dump_size);
9077 9077 break;
9078 9078 }
9079 9079
9080 9080 case FCIO_GET_TOPOLOGY: {
9081 9081 uint32_t user_topology;
9082 9082
9083 9083 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9084 9084 fcio->fcio_olen != sizeof (user_topology)) {
9085 9085 rval = EINVAL;
9086 9086 break;
9087 9087 }
9088 9088
9089 9089 mutex_enter(&port->fp_mutex);
9090 9090 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9091 9091 user_topology = FC_TOP_UNKNOWN;
9092 9092 } else {
9093 9093 user_topology = port->fp_topology;
9094 9094 }
9095 9095 mutex_exit(&port->fp_mutex);
9096 9096
9097 9097 if (ddi_copyout((void *)&user_topology,
9098 9098 (void *)fcio->fcio_obuf, sizeof (user_topology),
9099 9099 mode)) {
9100 9100 rval = EFAULT;
9101 9101 }
9102 9102 break;
9103 9103 }
9104 9104
9105 9105 case FCIO_RESET_LINK: {
9106 9106 la_wwn_t pwwn;
9107 9107
9108 9108 /*
9109 9109 * Look at the output buffer field; if this field has zero
9110 9110 * bytes then attempt to reset the local link/loop. If the
9111 9111 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9112 9112 * and if yes, determine the LFA and reset the remote LIP
9113 9113 * by LINIT ELS.
9114 9114 */
9115 9115
9116 9116 if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9117 9117 fcio->fcio_ilen != sizeof (pwwn)) {
9118 9118 rval = EINVAL;
9119 9119 break;
9120 9120 }
9121 9121
9122 9122 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9123 9123 sizeof (pwwn), mode)) {
9124 9124 rval = EFAULT;
9125 9125 break;
9126 9126 }
9127 9127
9128 9128 mutex_enter(&port->fp_mutex);
9129 9129 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9130 9130 mutex_exit(&port->fp_mutex);
9131 9131 break;
9132 9132 }
9133 9133 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9134 9134 mutex_exit(&port->fp_mutex);
9135 9135
9136 9136 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9137 9137 if (job == NULL) {
9138 9138 rval = ENOMEM;
9139 9139 break;
9140 9140 }
9141 9141 job->job_counter = 1;
9142 9142 job->job_private = (void *)&pwwn;
9143 9143
9144 9144 fctl_enque_job(port, job);
9145 9145 fctl_jobwait(job);
9146 9146
9147 9147 mutex_enter(&port->fp_mutex);
9148 9148 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9149 9149 mutex_exit(&port->fp_mutex);
9150 9150
9151 9151 if (job->job_result != FC_SUCCESS) {
9152 9152 fcio->fcio_errno = job->job_result;
9153 9153 rval = EIO;
9154 9154 if (fp_fcio_copyout(fcio, data, mode)) {
9155 9155 rval = EFAULT;
9156 9156 }
9157 9157 }
9158 9158 fctl_dealloc_job(job);
9159 9159 break;
9160 9160 }
9161 9161
9162 9162 case FCIO_RESET_HARD:
9163 9163 ret = port->fp_fca_tran->fca_reset(
9164 9164 port->fp_fca_handle, FC_FCA_RESET);
9165 9165 if (ret != FC_SUCCESS) {
9166 9166 fcio->fcio_errno = ret;
9167 9167 rval = EIO;
9168 9168 if (fp_fcio_copyout(fcio, data, mode)) {
9169 9169 rval = EFAULT;
9170 9170 }
9171 9171 }
9172 9172 break;
9173 9173
9174 9174 case FCIO_RESET_HARD_CORE:
9175 9175 ret = port->fp_fca_tran->fca_reset(
9176 9176 port->fp_fca_handle, FC_FCA_RESET_CORE);
9177 9177 if (ret != FC_SUCCESS) {
9178 9178 rval = EIO;
9179 9179 fcio->fcio_errno = ret;
9180 9180 if (fp_fcio_copyout(fcio, data, mode)) {
9181 9181 rval = EFAULT;
9182 9182 }
9183 9183 }
9184 9184 break;
9185 9185
9186 9186 case FCIO_DIAG: {
9187 9187 fc_fca_pm_t pm;
9188 9188
9189 9189 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9190 9190
9191 9191 /* Validate user buffer from ioctl call. */
9192 9192 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9193 9193 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9194 9194 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9195 9195 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9196 9196 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9197 9197 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9198 9198 rval = EFAULT;
9199 9199 break;
9200 9200 }
9201 9201
9202 9202 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9203 9203 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9204 9204 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9205 9205 fcio->fcio_ilen, mode)) {
9206 9206 rval = EFAULT;
9207 9207 goto fp_fcio_diag_cleanup;
9208 9208 }
9209 9209 }
9210 9210
9211 9211 if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9212 9212 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9213 9213 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9214 9214 fcio->fcio_alen, mode)) {
9215 9215 rval = EFAULT;
9216 9216 goto fp_fcio_diag_cleanup;
9217 9217 }
9218 9218 }
9219 9219
9220 9220 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9221 9221 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9222 9222 }
9223 9223
9224 9224 pm.pm_cmd_code = FC_PORT_DIAG;
9225 9225 pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9226 9226
9227 9227 ret = port->fp_fca_tran->fca_port_manage(
9228 9228 port->fp_fca_handle, &pm);
9229 9229
9230 9230 if (ret != FC_SUCCESS) {
9231 9231 if (ret == FC_INVALID_REQUEST) {
9232 9232 rval = ENOTTY;
9233 9233 } else {
9234 9234 rval = EIO;
9235 9235 }
9236 9236
9237 9237 fcio->fcio_errno = ret;
9238 9238 if (fp_fcio_copyout(fcio, data, mode)) {
9239 9239 rval = EFAULT;
9240 9240 }
9241 9241 goto fp_fcio_diag_cleanup;
9242 9242 }
9243 9243
9244 9244 /*
9245 9245 * pm_stat_len will contain the number of status bytes
9246 9246 * an FCA driver requires to return the complete status
9247 9247 * of the requested diag operation. If the user buffer
9248 9248 * is not large enough to hold the entire status, We
9249 9249 * copy only the portion of data the fits in the buffer and
9250 9250 * return a ENOMEM to the user application.
9251 9251 */
9252 9252 if (pm.pm_stat_len > fcio->fcio_olen) {
9253 9253 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9254 9254 "fp:FCIO_DIAG:status buffer too small\n");
9255 9255
9256 9256 rval = ENOMEM;
9257 9257 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9258 9258 fcio->fcio_olen, mode)) {
9259 9259 rval = EFAULT;
9260 9260 goto fp_fcio_diag_cleanup;
9261 9261 }
9262 9262 } else {
9263 9263 /*
9264 9264 * Copy only data pm_stat_len bytes of data
9265 9265 */
9266 9266 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9267 9267 pm.pm_stat_len, mode)) {
9268 9268 rval = EFAULT;
9269 9269 goto fp_fcio_diag_cleanup;
9270 9270 }
9271 9271 }
9272 9272
9273 9273 if (fp_fcio_copyout(fcio, data, mode)) {
9274 9274 rval = EFAULT;
9275 9275 }
9276 9276
9277 9277 fp_fcio_diag_cleanup:
9278 9278 if (pm.pm_cmd_buf != NULL) {
9279 9279 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9280 9280 }
9281 9281 if (pm.pm_data_buf != NULL) {
9282 9282 kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9283 9283 }
9284 9284 if (pm.pm_stat_buf != NULL) {
9285 9285 kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9286 9286 }
9287 9287
9288 9288 break;
9289 9289 }
9290 9290
9291 9291 case FCIO_GET_NODE_ID: {
9292 9292 /* validate parameters */
9293 9293 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9294 9294 fcio->fcio_olen < sizeof (fc_rnid_t)) {
9295 9295 rval = EINVAL;
9296 9296 break;
9297 9297 }
9298 9298
9299 9299 rval = fp_get_rnid(port, data, mode, fcio);
9300 9300
9301 9301 /* ioctl handling is over */
9302 9302 break;
9303 9303 }
9304 9304
9305 9305 case FCIO_SEND_NODE_ID: {
9306 9306 la_wwn_t pwwn;
9307 9307
9308 9308 /* validate parameters */
9309 9309 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9310 9310 fcio->fcio_xfer != FCIO_XFER_READ) {
9311 9311 rval = EINVAL;
9312 9312 break;
9313 9313 }
9314 9314
9315 9315 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9316 9316 sizeof (la_wwn_t), mode)) {
9317 9317 rval = EFAULT;
9318 9318 break;
9319 9319 }
9320 9320
9321 9321 rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9322 9322
9323 9323 /* ioctl handling is over */
9324 9324 break;
9325 9325 }
9326 9326
9327 9327 case FCIO_SET_NODE_ID: {
9328 9328 if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9329 9329 (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9330 9330 rval = EINVAL;
9331 9331 break;
9332 9332 }
9333 9333
9334 9334 rval = fp_set_rnid(port, data, mode, fcio);
9335 9335 break;
9336 9336 }
9337 9337
9338 9338 case FCIO_LINK_STATUS: {
9339 9339 fc_portid_t rls_req;
9340 9340 fc_rls_acc_t *rls_acc;
9341 9341 fc_fca_pm_t pm;
9342 9342 uint32_t dest, src_id;
9343 9343 fp_cmd_t *cmd;
9344 9344 fc_remote_port_t *pd;
9345 9345 uchar_t pd_flags;
9346 9346
9347 9347 /* validate parameters */
9348 9348 if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9349 9349 fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9350 9350 fcio->fcio_xfer != FCIO_XFER_RW) {
9351 9351 rval = EINVAL;
9352 9352 break;
9353 9353 }
9354 9354
9355 9355 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9356 9356 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9357 9357 rval = EINVAL;
9358 9358 break;
9359 9359 }
9360 9360
9361 9361 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9362 9362 sizeof (fc_portid_t), mode)) {
9363 9363 rval = EFAULT;
9364 9364 break;
9365 9365 }
9366 9366
9367 9367
9368 9368 /* Determine the destination of the RLS frame */
9369 9369 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9370 9370 dest = FS_FABRIC_F_PORT;
9371 9371 } else {
9372 9372 dest = rls_req.port_id;
9373 9373 }
9374 9374
9375 9375 mutex_enter(&port->fp_mutex);
9376 9376 src_id = port->fp_port_id.port_id;
9377 9377 mutex_exit(&port->fp_mutex);
9378 9378
9379 9379 /* If dest is zero OR same as FCA ID, then use port_manage() */
9380 9380 if (dest == 0 || dest == src_id) {
9381 9381
9382 9382 /* Allocate memory for link error status block */
9383 9383 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9384 9384 ASSERT(rls_acc != NULL);
9385 9385
9386 9386 /* Prepare the port management structure */
9387 9387 bzero((caddr_t)&pm, sizeof (pm));
9388 9388
9389 9389 pm.pm_cmd_flags = FC_FCA_PM_READ;
9390 9390 pm.pm_cmd_code = FC_PORT_RLS;
9391 9391 pm.pm_data_len = sizeof (*rls_acc);
9392 9392 pm.pm_data_buf = (caddr_t)rls_acc;
9393 9393
9394 9394 /* Get the adapter's link error status block */
9395 9395 ret = port->fp_fca_tran->fca_port_manage(
9396 9396 port->fp_fca_handle, &pm);
9397 9397
9398 9398 if (ret == FC_SUCCESS) {
9399 9399 /* xfer link status block to userland */
9400 9400 if (ddi_copyout((void *)rls_acc,
9401 9401 (void *)fcio->fcio_obuf,
9402 9402 sizeof (*rls_acc), mode) == 0) {
9403 9403 if (fp_fcio_copyout(fcio, data,
9404 9404 mode)) {
9405 9405 rval = EFAULT;
9406 9406 }
9407 9407 } else {
9408 9408 rval = EFAULT;
9409 9409 }
9410 9410 } else {
9411 9411 rval = EIO;
9412 9412 fcio->fcio_errno = ret;
9413 9413 if (fp_fcio_copyout(fcio, data, mode)) {
9414 9414 rval = EFAULT;
9415 9415 }
9416 9416 }
9417 9417
9418 9418 kmem_free(rls_acc, sizeof (*rls_acc));
9419 9419
9420 9420 /* ioctl handling is over */
9421 9421 break;
9422 9422 }
9423 9423
9424 9424 /*
9425 9425 * Send RLS to the destination port.
9426 9426 * Having RLS frame destination is as FPORT is not yet
9427 9427 * supported and will be implemented in future, if needed.
9428 9428 * Following call to get "pd" will fail if dest is FPORT
9429 9429 */
9430 9430 pd = fctl_hold_remote_port_by_did(port, dest);
9431 9431 if (pd == NULL) {
9432 9432 fcio->fcio_errno = FC_BADOBJECT;
9433 9433 rval = ENXIO;
9434 9434 if (fp_fcio_copyout(fcio, data, mode)) {
9435 9435 rval = EFAULT;
9436 9436 }
9437 9437 break;
9438 9438 }
9439 9439
9440 9440 mutex_enter(&pd->pd_mutex);
9441 9441 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9442 9442 mutex_exit(&pd->pd_mutex);
9443 9443 fctl_release_remote_port(pd);
9444 9444
9445 9445 fcio->fcio_errno = FC_LOGINREQ;
9446 9446 rval = EINVAL;
9447 9447 if (fp_fcio_copyout(fcio, data, mode)) {
9448 9448 rval = EFAULT;
9449 9449 }
9450 9450 break;
9451 9451 }
9452 9452 ASSERT(pd->pd_login_count >= 1);
9453 9453 mutex_exit(&pd->pd_mutex);
9454 9454
9455 9455 /*
9456 9456 * Allocate job structure and set job_code as DUMMY,
9457 9457 * because we will not go through the job thread.
9458 9458 * Instead fp_sendcmd() is called directly here.
9459 9459 */
9460 9460 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9461 9461 NULL, NULL, KM_SLEEP);
9462 9462 ASSERT(job != NULL);
9463 9463
9464 9464 job->job_counter = 1;
9465 9465
9466 9466 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9467 9467 sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9468 9468 if (cmd == NULL) {
9469 9469 fcio->fcio_errno = FC_NOMEM;
9470 9470 rval = ENOMEM;
9471 9471
9472 9472 fctl_release_remote_port(pd);
9473 9473
9474 9474 fctl_dealloc_job(job);
9475 9475 if (fp_fcio_copyout(fcio, data, mode)) {
9476 9476 rval = EFAULT;
9477 9477 }
9478 9478 break;
9479 9479 }
9480 9480
9481 9481 /* Allocate memory for link error status block */
9482 9482 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9483 9483
9484 9484 mutex_enter(&port->fp_mutex);
9485 9485 mutex_enter(&pd->pd_mutex);
9486 9486
9487 9487 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9488 9488 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9489 9489 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9490 9490 cmd->cmd_retry_count = 1;
9491 9491 cmd->cmd_ulp_pkt = NULL;
9492 9492
9493 9493 fp_rls_init(cmd, job);
9494 9494
9495 9495 job->job_private = (void *)rls_acc;
9496 9496
9497 9497 pd_flags = pd->pd_flags;
9498 9498 pd->pd_flags = PD_ELS_IN_PROGRESS;
9499 9499
9500 9500 mutex_exit(&pd->pd_mutex);
9501 9501 mutex_exit(&port->fp_mutex);
9502 9502
9503 9503 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9504 9504 fctl_jobwait(job);
9505 9505
9506 9506 fcio->fcio_errno = job->job_result;
9507 9507 if (job->job_result == FC_SUCCESS) {
9508 9508 ASSERT(pd != NULL);
9509 9509 /*
9510 9510 * link error status block is now available.
9511 9511 * Copy it to userland
9512 9512 */
9513 9513 ASSERT(job->job_private == (void *)rls_acc);
9514 9514 if (ddi_copyout((void *)rls_acc,
9515 9515 (void *)fcio->fcio_obuf,
9516 9516 sizeof (*rls_acc), mode) == 0) {
9517 9517 if (fp_fcio_copyout(fcio, data,
9518 9518 mode)) {
9519 9519 rval = EFAULT;
9520 9520 }
9521 9521 } else {
9522 9522 rval = EFAULT;
9523 9523 }
9524 9524 } else {
9525 9525 rval = EIO;
9526 9526 }
9527 9527 } else {
9528 9528 rval = EIO;
9529 9529 fp_free_pkt(cmd);
9530 9530 }
9531 9531
9532 9532 if (rval) {
9533 9533 mutex_enter(&port->fp_mutex);
9534 9534 mutex_enter(&pd->pd_mutex);
9535 9535 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9536 9536 pd->pd_flags = pd_flags;
9537 9537 }
9538 9538 mutex_exit(&pd->pd_mutex);
9539 9539 mutex_exit(&port->fp_mutex);
9540 9540 }
9541 9541
9542 9542 fctl_release_remote_port(pd);
9543 9543 fctl_dealloc_job(job);
9544 9544 kmem_free(rls_acc, sizeof (*rls_acc));
9545 9545
9546 9546 if (fp_fcio_copyout(fcio, data, mode)) {
9547 9547 rval = EFAULT;
9548 9548 }
9549 9549 break;
9550 9550 }
9551 9551
9552 9552 case FCIO_NS: {
9553 9553 fc_ns_cmd_t *ns_req;
9554 9554 fc_ns_cmd32_t *ns_req32;
9555 9555 fctl_ns_req_t *ns_cmd;
9556 9556
9557 9557 if (use32 == B_TRUE) {
9558 9558 if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9559 9559 rval = EINVAL;
9560 9560 break;
9561 9561 }
9562 9562
9563 9563 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9564 9564 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9565 9565
9566 9566 if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9567 9567 sizeof (*ns_req32), mode)) {
9568 9568 rval = EFAULT;
9569 9569 kmem_free(ns_req, sizeof (*ns_req));
9570 9570 kmem_free(ns_req32, sizeof (*ns_req32));
9571 9571 break;
9572 9572 }
9573 9573
9574 9574 ns_req->ns_flags = ns_req32->ns_flags;
9575 9575 ns_req->ns_cmd = ns_req32->ns_cmd;
9576 9576 ns_req->ns_req_len = ns_req32->ns_req_len;
9577 9577 ns_req->ns_req_payload = ns_req32->ns_req_payload;
9578 9578 ns_req->ns_resp_len = ns_req32->ns_resp_len;
9579 9579 ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9580 9580 ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9581 9581 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9582 9582
9583 9583 kmem_free(ns_req32, sizeof (*ns_req32));
9584 9584 } else {
9585 9585 if (fcio->fcio_ilen != sizeof (*ns_req)) {
9586 9586 rval = EINVAL;
9587 9587 break;
9588 9588 }
9589 9589
9590 9590 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9591 9591
9592 9592 if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9593 9593 sizeof (fc_ns_cmd_t), mode)) {
9594 9594 rval = EFAULT;
9595 9595 kmem_free(ns_req, sizeof (*ns_req));
9596 9596 break;
9597 9597 }
9598 9598 }
9599 9599
9600 9600 if (ns_req->ns_req_len <= 0) {
9601 9601 rval = EINVAL;
9602 9602 kmem_free(ns_req, sizeof (*ns_req));
9603 9603 break;
9604 9604 }
9605 9605
9606 9606 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9607 9607 ASSERT(job != NULL);
9608 9608
9609 9609 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9610 9610 ns_req->ns_resp_len, ns_req->ns_resp_len,
9611 9611 FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9612 9612 ASSERT(ns_cmd != NULL);
9613 9613 ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9614 9614
9615 9615 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9616 9616 ns_cmd->ns_gan_max = 1;
9617 9617 ns_cmd->ns_gan_index = 0;
9618 9618 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9619 9619 }
9620 9620
9621 9621 if (ddi_copyin(ns_req->ns_req_payload,
9622 9622 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9623 9623 rval = EFAULT;
9624 9624 fctl_free_ns_cmd(ns_cmd);
9625 9625 fctl_dealloc_job(job);
9626 9626 kmem_free(ns_req, sizeof (*ns_req));
9627 9627 break;
9628 9628 }
9629 9629
9630 9630 job->job_private = (void *)ns_cmd;
9631 9631 fctl_enque_job(port, job);
9632 9632 fctl_jobwait(job);
9633 9633 rval = job->job_result;
9634 9634
9635 9635 if (rval == FC_SUCCESS) {
9636 9636 if (ns_req->ns_resp_len) {
9637 9637 if (ddi_copyout(ns_cmd->ns_data_buf,
9638 9638 ns_req->ns_resp_payload,
9639 9639 ns_cmd->ns_data_len, mode)) {
9640 9640 rval = EFAULT;
9641 9641 fctl_free_ns_cmd(ns_cmd);
9642 9642 fctl_dealloc_job(job);
9643 9643 kmem_free(ns_req, sizeof (*ns_req));
9644 9644 break;
9645 9645 }
9646 9646 }
9647 9647 } else {
9648 9648 rval = EIO;
9649 9649 }
9650 9650 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9651 9651 fctl_free_ns_cmd(ns_cmd);
9652 9652 fctl_dealloc_job(job);
9653 9653 kmem_free(ns_req, sizeof (*ns_req));
9654 9654
9655 9655 if (fp_fcio_copyout(fcio, data, mode)) {
9656 9656 rval = EFAULT;
9657 9657 }
9658 9658 break;
9659 9659 }
9660 9660
9661 9661 default:
9662 9662 rval = ENOTTY;
9663 9663 break;
9664 9664 }
9665 9665
9666 9666 /*
9667 9667 * If set, reset the EXCL busy bit to
9668 9668 * receive other exclusive access commands
9669 9669 */
9670 9670 mutex_enter(&port->fp_mutex);
9671 9671 if (port->fp_flag & FP_EXCL_BUSY) {
9672 9672 port->fp_flag &= ~FP_EXCL_BUSY;
9673 9673 }
9674 9674 mutex_exit(&port->fp_mutex);
9675 9675
9676 9676 return (rval);
9677 9677 }
9678 9678
9679 9679
9680 9680 /*
9681 9681 * This function assumes that the response length
9682 9682 * is same regardless of data model (LP32 or LP64)
9683 9683 * which is true for all the ioctls currently
9684 9684 * supported.
9685 9685 */
9686 9686 static int
9687 9687 fp_copyout(void *from, void *to, size_t len, int mode)
9688 9688 {
9689 9689 return (ddi_copyout(from, to, len, mode));
9690 9690 }
9691 9691
9692 9692 /*
9693 9693 * This function does the set rnid
9694 9694 */
9695 9695 static int
9696 9696 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9697 9697 {
9698 9698 int rval = 0;
9699 9699 fc_rnid_t *rnid;
9700 9700 fc_fca_pm_t pm;
9701 9701
9702 9702 /* Allocate memory for node id block */
9703 9703 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9704 9704
9705 9705 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9706 9706 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9707 9707 kmem_free(rnid, sizeof (fc_rnid_t));
9708 9708 return (EFAULT);
9709 9709 }
9710 9710
9711 9711 /* Prepare the port management structure */
9712 9712 bzero((caddr_t)&pm, sizeof (pm));
9713 9713
9714 9714 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9715 9715 pm.pm_cmd_code = FC_PORT_SET_NODE_ID;
9716 9716 pm.pm_data_len = sizeof (*rnid);
9717 9717 pm.pm_data_buf = (caddr_t)rnid;
9718 9718
9719 9719 /* Get the adapter's node data */
9720 9720 rval = port->fp_fca_tran->fca_port_manage(
9721 9721 port->fp_fca_handle, &pm);
9722 9722
9723 9723 if (rval != FC_SUCCESS) {
9724 9724 fcio->fcio_errno = rval;
9725 9725 rval = EIO;
9726 9726 if (fp_fcio_copyout(fcio, data, mode)) {
9727 9727 rval = EFAULT;
9728 9728 }
9729 9729 } else {
9730 9730 mutex_enter(&port->fp_mutex);
9731 9731 /* copy to the port structure */
9732 9732 bcopy(rnid, &port->fp_rnid_params,
9733 9733 sizeof (port->fp_rnid_params));
9734 9734 mutex_exit(&port->fp_mutex);
9735 9735 }
9736 9736
9737 9737 kmem_free(rnid, sizeof (fc_rnid_t));
9738 9738
9739 9739 if (rval != FC_SUCCESS) {
9740 9740 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9741 9741 }
9742 9742
9743 9743 return (rval);
9744 9744 }
9745 9745
9746 9746 /*
9747 9747 * This function does the local pwwn get rnid
9748 9748 */
9749 9749 static int
9750 9750 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9751 9751 {
9752 9752 fc_rnid_t *rnid;
9753 9753 fc_fca_pm_t pm;
9754 9754 int rval = 0;
9755 9755 uint32_t ret;
9756 9756
9757 9757 /* Allocate memory for rnid data block */
9758 9758 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9759 9759
9760 9760 mutex_enter(&port->fp_mutex);
9761 9761 if (port->fp_rnid_init == 1) {
9762 9762 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9763 9763 mutex_exit(&port->fp_mutex);
9764 9764 /* xfer node info to userland */
9765 9765 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9766 9766 sizeof (*rnid), mode) == 0) {
9767 9767 if (fp_fcio_copyout(fcio, data, mode)) {
9768 9768 rval = EFAULT;
9769 9769 }
9770 9770 } else {
9771 9771 rval = EFAULT;
9772 9772 }
9773 9773
9774 9774 kmem_free(rnid, sizeof (fc_rnid_t));
9775 9775
9776 9776 if (rval != FC_SUCCESS) {
9777 9777 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9778 9778 rval);
9779 9779 }
9780 9780
9781 9781 return (rval);
9782 9782 }
9783 9783 mutex_exit(&port->fp_mutex);
9784 9784
9785 9785 /* Prepare the port management structure */
9786 9786 bzero((caddr_t)&pm, sizeof (pm));
9787 9787
9788 9788 pm.pm_cmd_flags = FC_FCA_PM_READ;
9789 9789 pm.pm_cmd_code = FC_PORT_GET_NODE_ID;
9790 9790 pm.pm_data_len = sizeof (fc_rnid_t);
9791 9791 pm.pm_data_buf = (caddr_t)rnid;
9792 9792
9793 9793 /* Get the adapter's node data */
9794 9794 ret = port->fp_fca_tran->fca_port_manage(
9795 9795 port->fp_fca_handle,
9796 9796 &pm);
9797 9797
9798 9798 if (ret == FC_SUCCESS) {
9799 9799 /* initialize in the port_info */
9800 9800 mutex_enter(&port->fp_mutex);
9801 9801 port->fp_rnid_init = 1;
9802 9802 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9803 9803 mutex_exit(&port->fp_mutex);
9804 9804
9805 9805 /* xfer node info to userland */
9806 9806 if (ddi_copyout((void *)rnid,
9807 9807 (void *)fcio->fcio_obuf,
9808 9808 sizeof (*rnid), mode) == 0) {
9809 9809 if (fp_fcio_copyout(fcio, data,
9810 9810 mode)) {
9811 9811 rval = EFAULT;
9812 9812 }
9813 9813 } else {
9814 9814 rval = EFAULT;
9815 9815 }
9816 9816 } else {
9817 9817 rval = EIO;
9818 9818 fcio->fcio_errno = ret;
9819 9819 if (fp_fcio_copyout(fcio, data, mode)) {
9820 9820 rval = EFAULT;
9821 9821 }
9822 9822 }
9823 9823
9824 9824 kmem_free(rnid, sizeof (fc_rnid_t));
9825 9825
9826 9826 if (rval != FC_SUCCESS) {
9827 9827 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9828 9828 }
9829 9829
9830 9830 return (rval);
9831 9831 }
9832 9832
9833 9833 static int
9834 9834 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9835 9835 la_wwn_t *pwwn)
9836 9836 {
9837 9837 int rval = 0;
9838 9838 fc_remote_port_t *pd;
9839 9839 fp_cmd_t *cmd;
9840 9840 job_request_t *job;
9841 9841 la_els_rnid_acc_t *rnid_acc;
9842 9842
9843 9843 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9844 9844 if (pd == NULL) {
9845 9845 /*
9846 9846 * We can safely assume that the destination port
9847 9847 * is logged in. Either the user land will explicitly
9848 9848 * login before issuing RNID ioctl or the device would
9849 9849 * have been configured, meaning already logged in.
9850 9850 */
9851 9851
9852 9852 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9853 9853
9854 9854 return (ENXIO);
9855 9855 }
9856 9856 /*
9857 9857 * Allocate job structure and set job_code as DUMMY,
9858 9858 * because we will not go thorugh the job thread.
9859 9859 * Instead fp_sendcmd() is called directly here.
9860 9860 */
9861 9861 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9862 9862 NULL, NULL, KM_SLEEP);
9863 9863
9864 9864 ASSERT(job != NULL);
9865 9865
9866 9866 job->job_counter = 1;
9867 9867
9868 9868 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9869 9869 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9870 9870 if (cmd == NULL) {
9871 9871 fcio->fcio_errno = FC_NOMEM;
9872 9872 rval = ENOMEM;
9873 9873
9874 9874 fctl_dealloc_job(job);
9875 9875 if (fp_fcio_copyout(fcio, data, mode)) {
9876 9876 rval = EFAULT;
9877 9877 }
9878 9878
9879 9879 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9880 9880
9881 9881 return (rval);
9882 9882 }
9883 9883
9884 9884 /* Allocate memory for node id accept block */
9885 9885 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9886 9886
9887 9887 mutex_enter(&port->fp_mutex);
9888 9888 mutex_enter(&pd->pd_mutex);
9889 9889
9890 9890 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9891 9891 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9892 9892 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9893 9893 cmd->cmd_retry_count = 1;
9894 9894 cmd->cmd_ulp_pkt = NULL;
9895 9895
9896 9896 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9897 9897
9898 9898 job->job_private = (void *)rnid_acc;
9899 9899
9900 9900 pd->pd_flags = PD_ELS_IN_PROGRESS;
9901 9901
9902 9902 mutex_exit(&pd->pd_mutex);
9903 9903 mutex_exit(&port->fp_mutex);
9904 9904
9905 9905 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9906 9906 fctl_jobwait(job);
9907 9907 fcio->fcio_errno = job->job_result;
9908 9908 if (job->job_result == FC_SUCCESS) {
9909 9909 int rnid_cnt;
9910 9910 ASSERT(pd != NULL);
9911 9911 /*
9912 9912 * node id block is now available.
9913 9913 * Copy it to userland
9914 9914 */
9915 9915 ASSERT(job->job_private == (void *)rnid_acc);
9916 9916
9917 9917 /* get the response length */
9918 9918 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9919 9919 rnid_acc->hdr.cmn_len +
9920 9920 rnid_acc->hdr.specific_len;
9921 9921
9922 9922 if (fcio->fcio_olen < rnid_cnt) {
9923 9923 rval = EINVAL;
9924 9924 } else if (ddi_copyout((void *)rnid_acc,
9925 9925 (void *)fcio->fcio_obuf,
9926 9926 rnid_cnt, mode) == 0) {
9927 9927 if (fp_fcio_copyout(fcio, data,
9928 9928 mode)) {
9929 9929 rval = EFAULT;
9930 9930 }
9931 9931 } else {
9932 9932 rval = EFAULT;
9933 9933 }
9934 9934 } else {
9935 9935 rval = EIO;
9936 9936 }
9937 9937 } else {
9938 9938 rval = EIO;
9939 9939 if (pd) {
9940 9940 mutex_enter(&pd->pd_mutex);
9941 9941 pd->pd_flags = PD_IDLE;
9942 9942 mutex_exit(&pd->pd_mutex);
9943 9943 }
9944 9944 fp_free_pkt(cmd);
9945 9945 }
9946 9946
9947 9947 fctl_dealloc_job(job);
9948 9948 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9949 9949
9950 9950 if (fp_fcio_copyout(fcio, data, mode)) {
9951 9951 rval = EFAULT;
9952 9952 }
9953 9953
9954 9954 if (rval != FC_SUCCESS) {
9955 9955 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9956 9956 }
9957 9957
9958 9958 return (rval);
9959 9959 }
9960 9960
9961 9961 /*
9962 9962 * Copy out to userland
9963 9963 */
9964 9964 static int
9965 9965 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9966 9966 {
9967 9967 int rval;
9968 9968
9969 9969 #ifdef _MULTI_DATAMODEL
9970 9970 switch (ddi_model_convert_from(mode & FMODELS)) {
9971 9971 case DDI_MODEL_ILP32: {
9972 9972 struct fcio32 fcio32;
9973 9973
9974 9974 fcio32.fcio_xfer = fcio->fcio_xfer;
9975 9975 fcio32.fcio_cmd = fcio->fcio_cmd;
9976 9976 fcio32.fcio_flags = fcio->fcio_flags;
9977 9977 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9978 9978 fcio32.fcio_ilen = fcio->fcio_ilen;
9979 9979 fcio32.fcio_ibuf =
9980 9980 (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9981 9981 fcio32.fcio_olen = fcio->fcio_olen;
9982 9982 fcio32.fcio_obuf =
9983 9983 (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9984 9984 fcio32.fcio_alen = fcio->fcio_alen;
9985 9985 fcio32.fcio_abuf =
9986 9986 (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9987 9987 fcio32.fcio_errno = fcio->fcio_errno;
9988 9988
9989 9989 rval = ddi_copyout((void *)&fcio32, (void *)data,
9990 9990 sizeof (struct fcio32), mode);
9991 9991 break;
9992 9992 }
9993 9993 case DDI_MODEL_NONE:
9994 9994 rval = ddi_copyout((void *)fcio, (void *)data,
9995 9995 sizeof (fcio_t), mode);
9996 9996 break;
9997 9997 }
9998 9998 #else
9999 9999 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
10000 10000 #endif
10001 10001
10002 10002 return (rval);
10003 10003 }
10004 10004
10005 10005
10006 10006 static void
10007 10007 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
10008 10008 {
10009 10009 uint32_t listlen;
10010 10010 fc_portmap_t *changelist;
10011 10011
10012 10012 ASSERT(MUTEX_HELD(&port->fp_mutex));
10013 10013 ASSERT(port->fp_topology == FC_TOP_PT_PT);
10014 10014 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10015 10015
10016 10016 listlen = 0;
10017 10017 changelist = NULL;
10018 10018
10019 10019 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10020 10020 if (port->fp_statec_busy > 1) {
10021 10021 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10022 10022 }
10023 10023 }
10024 10024 mutex_exit(&port->fp_mutex);
10025 10025
10026 10026 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10027 10027 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10028 10028 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10029 10029 listlen, listlen, KM_SLEEP);
10030 10030
10031 10031 mutex_enter(&port->fp_mutex);
10032 10032 } else {
10033 10033 ASSERT(changelist == NULL && listlen == 0);
10034 10034 mutex_enter(&port->fp_mutex);
10035 10035 if (--port->fp_statec_busy == 0) {
10036 10036 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10037 10037 }
10038 10038 }
10039 10039 }
10040 10040
10041 10041 static int
10042 10042 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10043 10043 {
10044 10044 int rval;
10045 10045 int count;
10046 10046 int index;
10047 10047 int num_devices;
10048 10048 fc_remote_node_t *node;
10049 10049 fc_port_dev_t *devlist;
10050 10050 struct pwwn_hash *head;
10051 10051 fc_remote_port_t *pd;
10052 10052
10053 10053 ASSERT(MUTEX_HELD(&port->fp_mutex));
10054 10054
10055 10055 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10056 10056
10057 10057 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
10058 10058
10059 10059 for (count = index = 0; index < pwwn_table_size; index++) {
10060 10060 head = &port->fp_pwwn_table[index];
10061 10061 pd = head->pwwn_head;
10062 10062 while (pd != NULL) {
10063 10063 mutex_enter(&pd->pd_mutex);
10064 10064 if (pd->pd_state == PORT_DEVICE_INVALID) {
10065 10065 mutex_exit(&pd->pd_mutex);
10066 10066 pd = pd->pd_wwn_hnext;
10067 10067 continue;
10068 10068 }
10069 10069
10070 10070 devlist[count].dev_state = pd->pd_state;
10071 10071 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10072 10072 devlist[count].dev_did = pd->pd_port_id;
10073 10073 devlist[count].dev_did.priv_lilp_posit =
10074 10074 (uint8_t)(index & 0xff);
10075 10075 bcopy((caddr_t)pd->pd_fc4types,
10076 10076 (caddr_t)devlist[count].dev_type,
10077 10077 sizeof (pd->pd_fc4types));
10078 10078
10079 10079 bcopy((caddr_t)&pd->pd_port_name,
10080 10080 (caddr_t)&devlist[count].dev_pwwn,
10081 10081 sizeof (la_wwn_t));
10082 10082
10083 10083 node = pd->pd_remote_nodep;
10084 10084 mutex_exit(&pd->pd_mutex);
10085 10085
10086 10086 if (node) {
10087 10087 mutex_enter(&node->fd_mutex);
10088 10088 bcopy((caddr_t)&node->fd_node_name,
10089 10089 (caddr_t)&devlist[count].dev_nwwn,
10090 10090 sizeof (la_wwn_t));
10091 10091 mutex_exit(&node->fd_mutex);
10092 10092 }
10093 10093 count++;
10094 10094 if (count >= num_devices) {
10095 10095 goto found;
10096 10096 }
10097 10097 }
10098 10098 }
10099 10099 found:
10100 10100 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10101 10101 sizeof (count), mode)) {
10102 10102 rval = FC_FAILURE;
10103 10103 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10104 10104 sizeof (fc_port_dev_t) * num_devices, mode)) {
10105 10105 rval = FC_FAILURE;
10106 10106 } else {
10107 10107 rval = FC_SUCCESS;
10108 10108 }
10109 10109
10110 10110 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10111 10111
10112 10112 return (rval);
10113 10113 }
10114 10114
10115 10115
10116 10116 /*
10117 10117 * Handle Fabric ONLINE
10118 10118 */
10119 10119 static void
10120 10120 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10121 10121 {
10122 10122 int index;
10123 10123 int rval;
10124 10124 int dbg_count;
10125 10125 int count = 0;
10126 10126 char ww_name[17];
10127 10127 uint32_t d_id;
10128 10128 uint32_t listlen;
10129 10129 fctl_ns_req_t *ns_cmd;
10130 10130 struct pwwn_hash *head;
10131 10131 fc_remote_port_t *pd;
10132 10132 fc_remote_port_t *npd;
10133 10133 fc_portmap_t *changelist;
10134 10134
10135 10135 ASSERT(MUTEX_HELD(&port->fp_mutex));
10136 10136 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10137 10137 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10138 10138
10139 10139 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10140 10140 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10141 10141 0, KM_SLEEP);
10142 10142
10143 10143 ASSERT(ns_cmd != NULL);
10144 10144
10145 10145 ns_cmd->ns_cmd_code = NS_GID_PN;
10146 10146
10147 10147 /*
10148 10148 * Check if orphans are showing up now
10149 10149 */
10150 10150 if (port->fp_orphan_count) {
10151 10151 fc_orphan_t *orp;
10152 10152 fc_orphan_t *norp = NULL;
10153 10153 fc_orphan_t *prev = NULL;
10154 10154
10155 10155 for (orp = port->fp_orphan_list; orp; orp = norp) {
10156 10156 norp = orp->orp_next;
10157 10157 mutex_exit(&port->fp_mutex);
10158 10158 orp->orp_nscan++;
10159 10159
10160 10160 job->job_counter = 1;
10161 10161 job->job_result = FC_SUCCESS;
10162 10162
10163 10163 ((ns_req_gid_pn_t *)
10164 10164 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10165 10165 ((ns_resp_gid_pn_t *)
10166 10166 ns_cmd->ns_data_buf)->pid.port_id = 0;
10167 10167 ((ns_resp_gid_pn_t *)
10168 10168 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10169 10169
10170 10170 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10171 10171 if (rval == FC_SUCCESS) {
10172 10172 d_id =
10173 10173 BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10174 10174 pd = fp_create_remote_port_by_ns(port,
10175 10175 d_id, KM_SLEEP);
10176 10176
10177 10177 if (pd != NULL) {
10178 10178 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10179 10179
10180 10180 fp_printf(port, CE_WARN, FP_LOG_ONLY,
10181 10181 0, NULL, "N_x Port with D_ID=%x,"
10182 10182 " PWWN=%s reappeared in fabric",
10183 10183 d_id, ww_name);
10184 10184
10185 10185 mutex_enter(&port->fp_mutex);
10186 10186 if (prev) {
10187 10187 prev->orp_next = orp->orp_next;
10188 10188 } else {
10189 10189 ASSERT(orp ==
10190 10190 port->fp_orphan_list);
10191 10191 port->fp_orphan_list =
10192 10192 orp->orp_next;
10193 10193 }
10194 10194 port->fp_orphan_count--;
10195 10195 mutex_exit(&port->fp_mutex);
10196 10196 kmem_free(orp, sizeof (*orp));
10197 10197 count++;
10198 10198
10199 10199 mutex_enter(&pd->pd_mutex);
10200 10200 pd->pd_flags = PD_ELS_MARK;
10201 10201
10202 10202 mutex_exit(&pd->pd_mutex);
10203 10203 } else {
10204 10204 prev = orp;
10205 10205 }
10206 10206 } else {
10207 10207 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10208 10208 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10209 10209
10210 10210 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10211 10211 NULL,
10212 10212 " Port WWN %s removed from orphan"
10213 10213 " list after %d scans", ww_name,
10214 10214 orp->orp_nscan);
10215 10215
10216 10216 mutex_enter(&port->fp_mutex);
10217 10217 if (prev) {
10218 10218 prev->orp_next = orp->orp_next;
10219 10219 } else {
10220 10220 ASSERT(orp ==
10221 10221 port->fp_orphan_list);
10222 10222 port->fp_orphan_list =
10223 10223 orp->orp_next;
10224 10224 }
10225 10225 port->fp_orphan_count--;
10226 10226 mutex_exit(&port->fp_mutex);
10227 10227
10228 10228 kmem_free(orp, sizeof (*orp));
10229 10229 } else {
10230 10230 prev = orp;
10231 10231 }
10232 10232 }
10233 10233 mutex_enter(&port->fp_mutex);
10234 10234 }
10235 10235 }
10236 10236
10237 10237 /*
10238 10238 * Walk the Port WWN hash table, reestablish LOGIN
10239 10239 * if a LOGIN is already performed on a particular
10240 10240 * device; Any failure to LOGIN should mark the
10241 10241 * port device OLD.
10242 10242 */
10243 10243 for (index = 0; index < pwwn_table_size; index++) {
10244 10244 head = &port->fp_pwwn_table[index];
10245 10245 npd = head->pwwn_head;
10246 10246
10247 10247 while ((pd = npd) != NULL) {
10248 10248 la_wwn_t *pwwn;
10249 10249
10250 10250 npd = pd->pd_wwn_hnext;
10251 10251
10252 10252 /*
10253 10253 * Don't count in the port devices that are new
10254 10254 * unless the total number of devices visible
10255 10255 * through this port is less than FP_MAX_DEVICES
10256 10256 */
10257 10257 mutex_enter(&pd->pd_mutex);
10258 10258 if (port->fp_dev_count >= FP_MAX_DEVICES ||
10259 10259 (port->fp_options & FP_TARGET_MODE)) {
10260 10260 if (pd->pd_type == PORT_DEVICE_NEW ||
10261 10261 pd->pd_flags == PD_ELS_MARK ||
10262 10262 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10263 10263 mutex_exit(&pd->pd_mutex);
10264 10264 continue;
10265 10265 }
10266 10266 } else {
10267 10267 if (pd->pd_flags == PD_ELS_MARK ||
10268 10268 pd->pd_recepient != PD_PLOGI_INITIATOR) {
10269 10269 mutex_exit(&pd->pd_mutex);
10270 10270 continue;
10271 10271 }
10272 10272 pd->pd_type = PORT_DEVICE_OLD;
10273 10273 }
10274 10274 count++;
10275 10275
10276 10276 /*
10277 10277 * Consult with the name server about D_ID changes
10278 10278 */
10279 10279 job->job_counter = 1;
10280 10280 job->job_result = FC_SUCCESS;
10281 10281
10282 10282 ((ns_req_gid_pn_t *)
10283 10283 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10284 10284 ((ns_resp_gid_pn_t *)
10285 10285 ns_cmd->ns_data_buf)->pid.port_id = 0;
10286 10286
10287 10287 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10288 10288 pid.priv_lilp_posit = 0;
10289 10289
10290 10290 pwwn = &pd->pd_port_name;
10291 10291 pd->pd_flags = PD_ELS_MARK;
10292 10292
10293 10293 mutex_exit(&pd->pd_mutex);
10294 10294 mutex_exit(&port->fp_mutex);
10295 10295
10296 10296 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10297 10297 if (rval != FC_SUCCESS) {
10298 10298 fc_wwn_to_str(pwwn, ww_name);
10299 10299
10300 10300 mutex_enter(&pd->pd_mutex);
10301 10301 d_id = pd->pd_port_id.port_id;
10302 10302 pd->pd_type = PORT_DEVICE_DELETE;
10303 10303 mutex_exit(&pd->pd_mutex);
10304 10304
10305 10305 FP_TRACE(FP_NHEAD1(3, 0),
10306 10306 "fp_fabric_online: PD "
10307 10307 "disappeared; d_id=%x, PWWN=%s",
10308 10308 d_id, ww_name);
10309 10309
10310 10310 FP_TRACE(FP_NHEAD2(9, 0),
10311 10311 "N_x Port with D_ID=%x, PWWN=%s"
10312 10312 " disappeared from fabric", d_id,
10313 10313 ww_name);
10314 10314
10315 10315 mutex_enter(&port->fp_mutex);
10316 10316 continue;
10317 10317 }
10318 10318
10319 10319 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10320 10320
10321 10321 mutex_enter(&port->fp_mutex);
10322 10322 mutex_enter(&pd->pd_mutex);
10323 10323 if (d_id != pd->pd_port_id.port_id) {
10324 10324 fctl_delist_did_table(port, pd);
10325 10325 fc_wwn_to_str(pwwn, ww_name);
10326 10326
10327 10327 FP_TRACE(FP_NHEAD2(9, 0),
10328 10328 "D_ID of a device with PWWN %s changed."
10329 10329 " New D_ID = %x, OLD D_ID = %x", ww_name,
10330 10330 d_id, pd->pd_port_id.port_id);
10331 10331
10332 10332 pd->pd_port_id.port_id = BE_32(d_id);
10333 10333 pd->pd_type = PORT_DEVICE_CHANGED;
10334 10334 fctl_enlist_did_table(port, pd);
10335 10335 }
10336 10336 mutex_exit(&pd->pd_mutex);
10337 10337
10338 10338 }
10339 10339 }
10340 10340
10341 10341 if (ns_cmd) {
10342 10342 fctl_free_ns_cmd(ns_cmd);
10343 10343 }
10344 10344
10345 10345 listlen = 0;
10346 10346 changelist = NULL;
10347 10347 if (count) {
10348 10348 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10349 10349 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10350 10350 mutex_exit(&port->fp_mutex);
10351 10351 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10352 10352 mutex_enter(&port->fp_mutex);
10353 10353 }
10354 10354
10355 10355 dbg_count = 0;
10356 10356
10357 10357 job->job_counter = count;
10358 10358
10359 10359 for (index = 0; index < pwwn_table_size; index++) {
10360 10360 head = &port->fp_pwwn_table[index];
10361 10361 npd = head->pwwn_head;
10362 10362
10363 10363 while ((pd = npd) != NULL) {
10364 10364 npd = pd->pd_wwn_hnext;
10365 10365
10366 10366 mutex_enter(&pd->pd_mutex);
10367 10367 if (pd->pd_flags != PD_ELS_MARK) {
10368 10368 mutex_exit(&pd->pd_mutex);
10369 10369 continue;
10370 10370 }
10371 10371
10372 10372 dbg_count++;
10373 10373
10374 10374 /*
10375 10375 * If it is already marked deletion, nothing
10376 10376 * else to do.
10377 10377 */
10378 10378 if (pd->pd_type == PORT_DEVICE_DELETE) {
10379 10379 pd->pd_type = PORT_DEVICE_OLD;
10380 10380
10381 10381 mutex_exit(&pd->pd_mutex);
10382 10382 mutex_exit(&port->fp_mutex);
10383 10383 fp_jobdone(job);
10384 10384 mutex_enter(&port->fp_mutex);
10385 10385
10386 10386 continue;
10387 10387 }
10388 10388
10389 10389 /*
10390 10390 * If it is freshly discovered out of
10391 10391 * the orphan list, nothing else to do
10392 10392 */
10393 10393 if (pd->pd_type == PORT_DEVICE_NEW) {
10394 10394 pd->pd_flags = PD_IDLE;
10395 10395
10396 10396 mutex_exit(&pd->pd_mutex);
10397 10397 mutex_exit(&port->fp_mutex);
10398 10398 fp_jobdone(job);
10399 10399 mutex_enter(&port->fp_mutex);
10400 10400
10401 10401 continue;
10402 10402 }
10403 10403
10404 10404 pd->pd_flags = PD_IDLE;
10405 10405 d_id = pd->pd_port_id.port_id;
10406 10406
10407 10407 /*
10408 10408 * Explicitly mark all devices OLD; successful
10409 10409 * PLOGI should reset this to either NO_CHANGE
10410 10410 * or CHANGED.
10411 10411 */
10412 10412 if (pd->pd_type != PORT_DEVICE_CHANGED) {
10413 10413 pd->pd_type = PORT_DEVICE_OLD;
10414 10414 }
10415 10415
10416 10416 mutex_exit(&pd->pd_mutex);
10417 10417 mutex_exit(&port->fp_mutex);
10418 10418
10419 10419 rval = fp_port_login(port, d_id, job,
10420 10420 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10421 10421
10422 10422 if (rval != FC_SUCCESS) {
10423 10423 fp_jobdone(job);
10424 10424 }
10425 10425 mutex_enter(&port->fp_mutex);
10426 10426 }
10427 10427 }
10428 10428 mutex_exit(&port->fp_mutex);
10429 10429
10430 10430 ASSERT(dbg_count == count);
10431 10431 fp_jobwait(job);
10432 10432
10433 10433 mutex_enter(&port->fp_mutex);
10434 10434
10435 10435 ASSERT(port->fp_statec_busy > 0);
10436 10436 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10437 10437 if (port->fp_statec_busy > 1) {
10438 10438 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10439 10439 }
10440 10440 }
10441 10441 mutex_exit(&port->fp_mutex);
10442 10442 } else {
10443 10443 ASSERT(port->fp_statec_busy > 0);
10444 10444 if (port->fp_statec_busy > 1) {
10445 10445 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10446 10446 }
10447 10447 mutex_exit(&port->fp_mutex);
10448 10448 }
10449 10449
10450 10450 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10451 10451 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10452 10452
10453 10453 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10454 10454 listlen, listlen, KM_SLEEP);
10455 10455
10456 10456 mutex_enter(&port->fp_mutex);
10457 10457 } else {
10458 10458 ASSERT(changelist == NULL && listlen == 0);
10459 10459 mutex_enter(&port->fp_mutex);
10460 10460 if (--port->fp_statec_busy == 0) {
10461 10461 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10462 10462 }
10463 10463 }
10464 10464 }
10465 10465
10466 10466
10467 10467 /*
10468 10468 * Fill out device list for userland ioctl in private loop
10469 10469 */
10470 10470 static int
10471 10471 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10472 10472 {
10473 10473 int rval;
10474 10474 int count;
10475 10475 int index;
10476 10476 int num_devices;
10477 10477 fc_remote_node_t *node;
10478 10478 fc_port_dev_t *devlist;
10479 10479 int lilp_device_count;
10480 10480 fc_lilpmap_t *lilp_map;
10481 10481 uchar_t *alpa_list;
10482 10482
10483 10483 ASSERT(MUTEX_HELD(&port->fp_mutex));
10484 10484
10485 10485 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10486 10486 if (port->fp_total_devices > port->fp_dev_count &&
10487 10487 num_devices >= port->fp_total_devices) {
10488 10488 job_request_t *job;
10489 10489
10490 10490 mutex_exit(&port->fp_mutex);
10491 10491 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10492 10492 job->job_counter = 1;
10493 10493
10494 10494 mutex_enter(&port->fp_mutex);
10495 10495 fp_get_loopmap(port, job);
10496 10496 mutex_exit(&port->fp_mutex);
10497 10497
10498 10498 fp_jobwait(job);
10499 10499 fctl_dealloc_job(job);
10500 10500 } else {
10501 10501 mutex_exit(&port->fp_mutex);
10502 10502 }
10503 10503 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10504 10504
10505 10505 mutex_enter(&port->fp_mutex);
10506 10506
10507 10507 /*
10508 10508 * Applications are accustomed to getting the device list in
10509 10509 * LILP map order. The HBA firmware usually returns the device
10510 10510 * map in the LILP map order and diagnostic applications would
10511 10511 * prefer to receive in the device list in that order too
10512 10512 */
10513 10513 lilp_map = &port->fp_lilp_map;
10514 10514 alpa_list = &lilp_map->lilp_alpalist[0];
10515 10515
10516 10516 /*
10517 10517 * the length field corresponds to the offset in the LILP frame
10518 10518 * which begins with 1. The thing to note here is that the
10519 10519 * lilp_device_count is 1 more than fp->fp_total_devices since
10520 10520 * the host adapter's alpa also shows up in the lilp map. We
10521 10521 * don't however return details of the host adapter since
10522 10522 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10523 10523 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10524 10524 * ioctl to obtain details about the host adapter port.
10525 10525 */
10526 10526 lilp_device_count = lilp_map->lilp_length;
10527 10527
10528 10528 for (count = index = 0; index < lilp_device_count &&
10529 10529 count < num_devices; index++) {
10530 10530 uint32_t d_id;
10531 10531 fc_remote_port_t *pd;
10532 10532
10533 10533 d_id = alpa_list[index];
10534 10534
10535 10535 mutex_exit(&port->fp_mutex);
10536 10536 pd = fctl_get_remote_port_by_did(port, d_id);
10537 10537 mutex_enter(&port->fp_mutex);
10538 10538
10539 10539 if (pd != NULL) {
10540 10540 mutex_enter(&pd->pd_mutex);
10541 10541
10542 10542 if (pd->pd_state == PORT_DEVICE_INVALID) {
10543 10543 mutex_exit(&pd->pd_mutex);
10544 10544 continue;
10545 10545 }
10546 10546
10547 10547 devlist[count].dev_state = pd->pd_state;
10548 10548 devlist[count].dev_hard_addr = pd->pd_hard_addr;
10549 10549 devlist[count].dev_did = pd->pd_port_id;
10550 10550 devlist[count].dev_did.priv_lilp_posit =
10551 10551 (uint8_t)(index & 0xff);
10552 10552 bcopy((caddr_t)pd->pd_fc4types,
10553 10553 (caddr_t)devlist[count].dev_type,
10554 10554 sizeof (pd->pd_fc4types));
10555 10555
10556 10556 bcopy((caddr_t)&pd->pd_port_name,
10557 10557 (caddr_t)&devlist[count].dev_pwwn,
10558 10558 sizeof (la_wwn_t));
10559 10559
10560 10560 node = pd->pd_remote_nodep;
10561 10561 mutex_exit(&pd->pd_mutex);
10562 10562
10563 10563 if (node) {
10564 10564 mutex_enter(&node->fd_mutex);
10565 10565 bcopy((caddr_t)&node->fd_node_name,
10566 10566 (caddr_t)&devlist[count].dev_nwwn,
10567 10567 sizeof (la_wwn_t));
10568 10568 mutex_exit(&node->fd_mutex);
10569 10569 }
10570 10570 count++;
10571 10571 }
10572 10572 }
10573 10573
10574 10574 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10575 10575 sizeof (count), mode)) {
10576 10576 rval = FC_FAILURE;
10577 10577 }
10578 10578
10579 10579 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10580 10580 sizeof (fc_port_dev_t) * num_devices, mode)) {
10581 10581 rval = FC_FAILURE;
10582 10582 } else {
10583 10583 rval = FC_SUCCESS;
10584 10584 }
10585 10585
10586 10586 kmem_free(devlist, sizeof (*devlist) * num_devices);
10587 10587 ASSERT(MUTEX_HELD(&port->fp_mutex));
10588 10588
10589 10589 return (rval);
10590 10590 }
10591 10591
10592 10592
10593 10593 /*
10594 10594 * Completion function for responses to unsolicited commands
10595 10595 */
10596 10596 static void
10597 10597 fp_unsol_intr(fc_packet_t *pkt)
10598 10598 {
10599 10599 fp_cmd_t *cmd;
10600 10600 fc_local_port_t *port;
10601 10601
10602 10602 cmd = pkt->pkt_ulp_private;
10603 10603 port = cmd->cmd_port;
10604 10604
10605 10605 mutex_enter(&port->fp_mutex);
10606 10606 port->fp_out_fpcmds--;
10607 10607 mutex_exit(&port->fp_mutex);
10608 10608
10609 10609 if (pkt->pkt_state != FC_PKT_SUCCESS) {
10610 10610 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10611 10611 "couldn't post response to unsolicited request;"
10612 10612 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10613 10613 pkt->pkt_resp_fhdr.rx_id);
10614 10614 }
10615 10615
10616 10616 if (cmd == port->fp_els_resp_pkt) {
10617 10617 mutex_enter(&port->fp_mutex);
10618 10618 port->fp_els_resp_pkt_busy = 0;
10619 10619 mutex_exit(&port->fp_mutex);
10620 10620 return;
10621 10621 }
10622 10622
10623 10623 fp_free_pkt(cmd);
10624 10624 }
10625 10625
10626 10626
10627 10627 /*
10628 10628 * solicited LINIT ELS completion function
10629 10629 */
10630 10630 static void
10631 10631 fp_linit_intr(fc_packet_t *pkt)
10632 10632 {
10633 10633 fp_cmd_t *cmd;
10634 10634 job_request_t *job;
10635 10635 fc_linit_resp_t acc;
10636 10636 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10637 10637
10638 10638 cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10639 10639
10640 10640 mutex_enter(&cmd->cmd_port->fp_mutex);
10641 10641 cmd->cmd_port->fp_out_fpcmds--;
10642 10642 mutex_exit(&cmd->cmd_port->fp_mutex);
10643 10643
10644 10644 if (FP_IS_PKT_ERROR(pkt)) {
10645 10645 (void) fp_common_intr(pkt, 1);
10646 10646 return;
10647 10647 }
10648 10648
10649 10649 job = cmd->cmd_job;
10650 10650
10651 10651 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10652 10652 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10653 10653 if (acc.status != FC_LINIT_SUCCESS) {
10654 10654 job->job_result = FC_FAILURE;
10655 10655 } else {
10656 10656 job->job_result = FC_SUCCESS;
10657 10657 }
10658 10658
10659 10659 fp_iodone(cmd);
10660 10660 }
10661 10661
10662 10662
10663 10663 /*
10664 10664 * Decode the unsolicited request; For FC-4 Device and Link data frames
10665 10665 * notify the registered ULP of this FC-4 type right here. For Unsolicited
10666 10666 * ELS requests, submit a request to the job_handler thread to work on it.
10667 10667 * The intent is to act quickly on the FC-4 unsolicited link and data frames
10668 10668 * and save much of the interrupt time processing of unsolicited ELS requests
10669 10669 * and hand it off to the job_handler thread.
10670 10670 */
10671 10671 static void
10672 10672 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10673 10673 {
10674 10674 uchar_t r_ctl;
10675 10675 uchar_t ls_code;
10676 10676 uint32_t s_id;
10677 10677 uint32_t rscn_count = FC_INVALID_RSCN_COUNT;
10678 10678 uint32_t cb_arg;
10679 10679 fp_cmd_t *cmd;
10680 10680 fc_local_port_t *port;
10681 10681 job_request_t *job;
10682 10682 fc_remote_port_t *pd;
10683 10683
10684 10684 port = port_handle;
10685 10685
10686 10686 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10687 10687 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10688 10688 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10689 10689 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10690 10690 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10691 10691 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10692 10692 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10693 10693 buf->ub_buffer[0]);
10694 10694
10695 10695 if (type & 0x80000000) {
10696 10696 /*
10697 10697 * Huh ? Nothing much can be done without
10698 10698 * a valid buffer. So just exit.
10699 10699 */
10700 10700 return;
10701 10701 }
10702 10702 /*
10703 10703 * If the unsolicited interrupts arrive while it isn't
10704 10704 * safe to handle unsolicited callbacks; Drop them, yes,
10705 10705 * drop them on the floor
10706 10706 */
10707 10707 mutex_enter(&port->fp_mutex);
10708 10708 port->fp_active_ubs++;
10709 10709 if ((port->fp_soft_state &
10710 10710 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10711 10711 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10712 10712
10713 10713 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10714 10714 "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10715 10715 "seq_id=%x, ox_id=%x, rx_id=%x"
10716 10716 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10717 10717 buf->ub_frame.type, buf->ub_frame.seq_id,
10718 10718 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10719 10719
10720 10720 ASSERT(port->fp_active_ubs > 0);
10721 10721 if (--(port->fp_active_ubs) == 0) {
10722 10722 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10723 10723 }
10724 10724
10725 10725 mutex_exit(&port->fp_mutex);
10726 10726
10727 10727 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10728 10728 1, &buf->ub_token);
10729 10729
10730 10730 return;
10731 10731 }
10732 10732
10733 10733 r_ctl = buf->ub_frame.r_ctl;
10734 10734 s_id = buf->ub_frame.s_id;
10735 10735 if (port->fp_active_ubs == 1) {
10736 10736 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10737 10737 }
10738 10738
10739 10739 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10740 10740 port->fp_statec_busy) {
10741 10741 mutex_exit(&port->fp_mutex);
10742 10742 pd = fctl_get_remote_port_by_did(port, s_id);
10743 10743 if (pd) {
10744 10744 mutex_enter(&pd->pd_mutex);
10745 10745 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10746 10746 FP_TRACE(FP_NHEAD1(3, 0),
10747 10747 "LOGO for LOGGED IN D_ID %x",
10748 10748 buf->ub_frame.s_id);
10749 10749 pd->pd_state = PORT_DEVICE_VALID;
10750 10750 }
10751 10751 mutex_exit(&pd->pd_mutex);
10752 10752 }
10753 10753
10754 10754 mutex_enter(&port->fp_mutex);
10755 10755 ASSERT(port->fp_active_ubs > 0);
10756 10756 if (--(port->fp_active_ubs) == 0) {
10757 10757 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10758 10758 }
10759 10759 mutex_exit(&port->fp_mutex);
10760 10760
10761 10761 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10762 10762 1, &buf->ub_token);
10763 10763
10764 10764 FP_TRACE(FP_NHEAD1(3, 0),
10765 10765 "fp_unsol_cb() bailing out LOGO for D_ID %x",
10766 10766 buf->ub_frame.s_id);
10767 10767 return;
10768 10768 }
10769 10769
10770 10770 if (port->fp_els_resp_pkt_busy == 0) {
10771 10771 if (r_ctl == R_CTL_ELS_REQ) {
10772 10772 ls_code = buf->ub_buffer[0];
10773 10773
10774 10774 switch (ls_code) {
10775 10775 case LA_ELS_PLOGI:
10776 10776 case LA_ELS_FLOGI:
10777 10777 port->fp_els_resp_pkt_busy = 1;
10778 10778 mutex_exit(&port->fp_mutex);
10779 10779 fp_i_handle_unsol_els(port, buf);
10780 10780
10781 10781 mutex_enter(&port->fp_mutex);
10782 10782 ASSERT(port->fp_active_ubs > 0);
10783 10783 if (--(port->fp_active_ubs) == 0) {
10784 10784 port->fp_soft_state &=
10785 10785 ~FP_SOFT_IN_UNSOL_CB;
10786 10786 }
10787 10787 mutex_exit(&port->fp_mutex);
10788 10788 port->fp_fca_tran->fca_ub_release(
10789 10789 port->fp_fca_handle, 1, &buf->ub_token);
10790 10790
10791 10791 return;
10792 10792 case LA_ELS_RSCN:
10793 10793 if (++(port)->fp_rscn_count ==
10794 10794 FC_INVALID_RSCN_COUNT) {
10795 10795 ++(port)->fp_rscn_count;
10796 10796 }
10797 10797 rscn_count = port->fp_rscn_count;
10798 10798 break;
10799 10799
10800 10800 default:
10801 10801 break;
10802 10802 }
10803 10803 }
10804 10804 } else if ((r_ctl == R_CTL_ELS_REQ) &&
10805 10805 (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10806 10806 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10807 10807 ++port->fp_rscn_count;
10808 10808 }
10809 10809 rscn_count = port->fp_rscn_count;
10810 10810 }
10811 10811
10812 10812 mutex_exit(&port->fp_mutex);
10813 10813
10814 10814 switch (r_ctl & R_CTL_ROUTING) {
10815 10815 case R_CTL_DEVICE_DATA:
10816 10816 /*
10817 10817 * If the unsolicited buffer is a CT IU,
10818 10818 * have the job_handler thread work on it.
10819 10819 */
10820 10820 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10821 10821 break;
10822 10822 }
10823 10823 /* FALLTHROUGH */
10824 10824
10825 10825 case R_CTL_FC4_SVC: {
10826 10826 int sendup = 0;
10827 10827
10828 10828 /*
10829 10829 * If a LOGIN isn't performed before this request
10830 10830 * shut the door on this port with a reply that a
10831 10831 * LOGIN is required. We make an exception however
10832 10832 * for IP broadcast packets and pass them through
10833 10833 * to the IP ULP(s) to handle broadcast requests.
10834 10834 * This is not a problem for private loop devices
10835 10835 * but for fabric topologies we don't log into the
10836 10836 * remote ports during port initialization and
10837 10837 * the ULPs need to log into requesting ports on
10838 10838 * demand.
10839 10839 */
10840 10840 pd = fctl_get_remote_port_by_did(port, s_id);
10841 10841 if (pd) {
10842 10842 mutex_enter(&pd->pd_mutex);
10843 10843 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10844 10844 sendup++;
10845 10845 }
10846 10846 mutex_exit(&pd->pd_mutex);
10847 10847 } else if ((pd == NULL) &&
10848 10848 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10849 10849 (buf->ub_frame.d_id == 0xffffff ||
10850 10850 buf->ub_frame.d_id == 0x00)) {
10851 10851 /* brodacst IP frame - so sendup via job thread */
10852 10852 break;
10853 10853 }
10854 10854
10855 10855 /*
10856 10856 * Send all FC4 services via job thread too
10857 10857 */
10858 10858 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10859 10859 break;
10860 10860 }
10861 10861
10862 10862 if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10863 10863 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10864 10864 return;
10865 10865 }
10866 10866
10867 10867 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10868 10868 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10869 10869 0, KM_NOSLEEP, pd);
10870 10870 if (cmd != NULL) {
10871 10871 fp_els_rjt_init(port, cmd, buf,
10872 10872 FC_ACTION_NON_RETRYABLE,
10873 10873 FC_REASON_LOGIN_REQUIRED, NULL);
10874 10874
10875 10875 if (fp_sendcmd(port, cmd,
10876 10876 port->fp_fca_handle) != FC_SUCCESS) {
10877 10877 fp_free_pkt(cmd);
10878 10878 }
10879 10879 }
10880 10880 }
10881 10881
10882 10882 mutex_enter(&port->fp_mutex);
10883 10883 ASSERT(port->fp_active_ubs > 0);
10884 10884 if (--(port->fp_active_ubs) == 0) {
10885 10885 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10886 10886 }
10887 10887 mutex_exit(&port->fp_mutex);
10888 10888 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10889 10889 1, &buf->ub_token);
10890 10890
10891 10891 return;
10892 10892 }
10893 10893
10894 10894 default:
10895 10895 break;
10896 10896 }
10897 10897
10898 10898 /*
10899 10899 * Submit a Request to the job_handler thread to work
10900 10900 * on the unsolicited request. The potential side effect
10901 10901 * of this is that the unsolicited buffer takes a little
10902 10902 * longer to get released but we save interrupt time in
10903 10903 * the bargain.
10904 10904 */
10905 10905 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10906 10906
10907 10907 /*
10908 10908 * One way that the rscn_count will get used is described below :
10909 10909 *
10910 10910 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10911 10911 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10912 10912 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10913 10913 * by overloading the job_cb_arg to pass the rscn_count
10914 10914 * 4. When one of the routines processing the RSCN picks it up (ex:
10915 10915 * fp_validate_rscn_page()), it passes this count in the map
10916 10916 * structure (as part of the map_rscn_info structure member) to the
10917 10917 * ULPs.
10918 10918 * 5. When ULPs make calls back to the transport (example interfaces for
10919 10919 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10920 10920 * can now pass back this count as part of the fc_packet's
10921 10921 * pkt_ulp_rscn_count member. fcp does this currently.
10922 10922 * 6. When transport gets a call to transport a command on the wire, it
10923 10923 * will check to see if there is a valid pkt_ulp_rsvd1 field in the
10924 10924 * fc_packet. If there is, it will match that info with the current
10925 10925 * rscn_count on that instance of the port. If they don't match up
10926 10926 * then there was a newer RSCN. The ULP gets back an error code which
10927 10927 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10928 10928 * 7. At this point the ULP is free to make up its own mind as to how to
10929 10929 * handle this. Currently, fcp will reset its retry counters and keep
10930 10930 * retrying the operation it was doing in anticipation of getting a
10931 10931 * new state change call back for the new RSCN.
10932 10932 */
10933 10933 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10934 10934 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10935 10935 if (job == NULL) {
10936 10936 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10937 10937 "couldn't submit a job to the thread, failing..");
10938 10938
10939 10939 mutex_enter(&port->fp_mutex);
10940 10940
10941 10941 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10942 10942 --port->fp_rscn_count;
10943 10943 }
10944 10944
10945 10945 ASSERT(port->fp_active_ubs > 0);
10946 10946 if (--(port->fp_active_ubs) == 0) {
10947 10947 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10948 10948 }
10949 10949
10950 10950 mutex_exit(&port->fp_mutex);
10951 10951 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10952 10952 1, &buf->ub_token);
10953 10953
10954 10954 return;
10955 10955 }
10956 10956 job->job_private = (void *)buf;
10957 10957 fctl_enque_job(port, job);
10958 10958 }
10959 10959
10960 10960
10961 10961 /*
10962 10962 * Handle unsolicited requests
10963 10963 */
10964 10964 static void
10965 10965 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10966 10966 job_request_t *job)
10967 10967 {
10968 10968 uchar_t r_ctl;
10969 10969 uchar_t ls_code;
10970 10970 uint32_t s_id;
10971 10971 fp_cmd_t *cmd;
10972 10972 fc_remote_port_t *pd;
10973 10973 fp_unsol_spec_t *ub_spec;
10974 10974
10975 10975 r_ctl = buf->ub_frame.r_ctl;
10976 10976 s_id = buf->ub_frame.s_id;
10977 10977
10978 10978 switch (r_ctl & R_CTL_ROUTING) {
10979 10979 case R_CTL_EXTENDED_SVC:
10980 10980 if (r_ctl != R_CTL_ELS_REQ) {
10981 10981 break;
10982 10982 }
10983 10983
10984 10984 ls_code = buf->ub_buffer[0];
10985 10985 switch (ls_code) {
10986 10986 case LA_ELS_LOGO:
10987 10987 case LA_ELS_ADISC:
10988 10988 case LA_ELS_PRLO:
10989 10989 pd = fctl_get_remote_port_by_did(port, s_id);
10990 10990 if (pd == NULL) {
10991 10991 if (!FC_IS_REAL_DEVICE(s_id)) {
10992 10992 break;
10993 10993 }
10994 10994 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10995 10995 break;
10996 10996 }
10997 10997 if ((cmd = fp_alloc_pkt(port,
10998 10998 sizeof (la_els_rjt_t), 0, KM_SLEEP,
10999 10999 NULL)) == NULL) {
11000 11000 /*
11001 11001 * Can this actually fail when
11002 11002 * given KM_SLEEP? (Could be used
11003 11003 * this way in a number of places.)
11004 11004 */
11005 11005 break;
11006 11006 }
11007 11007
11008 11008 fp_els_rjt_init(port, cmd, buf,
11009 11009 FC_ACTION_NON_RETRYABLE,
11010 11010 FC_REASON_INVALID_LINK_CTRL, job);
11011 11011
11012 11012 if (fp_sendcmd(port, cmd,
11013 11013 port->fp_fca_handle) != FC_SUCCESS) {
11014 11014 fp_free_pkt(cmd);
11015 11015 }
11016 11016
11017 11017 break;
11018 11018 }
11019 11019 if (ls_code == LA_ELS_LOGO) {
11020 11020 fp_handle_unsol_logo(port, buf, pd, job);
11021 11021 } else if (ls_code == LA_ELS_ADISC) {
11022 11022 fp_handle_unsol_adisc(port, buf, pd, job);
11023 11023 } else {
11024 11024 fp_handle_unsol_prlo(port, buf, pd, job);
11025 11025 }
11026 11026 break;
11027 11027
11028 11028 case LA_ELS_PLOGI:
11029 11029 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
11030 11030 break;
11031 11031
11032 11032 case LA_ELS_FLOGI:
11033 11033 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
11034 11034 break;
11035 11035
11036 11036 case LA_ELS_RSCN:
11037 11037 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
11038 11038 break;
11039 11039
11040 11040 default:
11041 11041 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11042 11042 ub_spec->port = port;
11043 11043 ub_spec->buf = buf;
11044 11044
11045 11045 (void) taskq_dispatch(port->fp_taskq,
11046 11046 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11047 11047 return;
11048 11048 }
11049 11049 break;
11050 11050
11051 11051 case R_CTL_BASIC_SVC:
11052 11052 /*
11053 11053 * The unsolicited basic link services could be ABTS
11054 11054 * and RMC (Or even a NOP). Just BA_RJT them until
11055 11055 * such time there arises a need to handle them more
11056 11056 * carefully.
11057 11057 */
11058 11058 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11059 11059 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
11060 11060 0, KM_SLEEP, NULL);
11061 11061 if (cmd != NULL) {
11062 11062 fp_ba_rjt_init(port, cmd, buf, job);
11063 11063 if (fp_sendcmd(port, cmd,
11064 11064 port->fp_fca_handle) != FC_SUCCESS) {
11065 11065 fp_free_pkt(cmd);
11066 11066 }
11067 11067 }
11068 11068 }
11069 11069 break;
11070 11070
11071 11071 case R_CTL_DEVICE_DATA:
11072 11072 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11073 11073 /*
11074 11074 * Mostly this is of type FC_TYPE_FC_SERVICES.
11075 11075 * As we don't like any Unsolicited FC services
11076 11076 * requests, we would do well to RJT them as
11077 11077 * well.
11078 11078 */
11079 11079 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11080 11080 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11081 11081 0, KM_SLEEP, NULL);
11082 11082 if (cmd != NULL) {
11083 11083 fp_els_rjt_init(port, cmd, buf,
11084 11084 FC_ACTION_NON_RETRYABLE,
11085 11085 FC_REASON_INVALID_LINK_CTRL, job);
11086 11086
11087 11087 if (fp_sendcmd(port, cmd,
11088 11088 port->fp_fca_handle) !=
11089 11089 FC_SUCCESS) {
11090 11090 fp_free_pkt(cmd);
11091 11091 }
11092 11092 }
11093 11093 }
11094 11094 break;
11095 11095 }
11096 11096 /* FALLTHROUGH */
11097 11097
11098 11098 case R_CTL_FC4_SVC:
11099 11099 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11100 11100 ub_spec->port = port;
11101 11101 ub_spec->buf = buf;
11102 11102
11103 11103 (void) taskq_dispatch(port->fp_taskq,
11104 11104 fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11105 11105 return;
11106 11106
11107 11107 case R_CTL_LINK_CTL:
11108 11108 /*
11109 11109 * Turn deaf ear on unsolicited link control frames.
11110 11110 * Typical unsolicited link control Frame is an LCR
11111 11111 * (to reset End to End credit to the default login
11112 11112 * value and abort current sequences for all classes)
11113 11113 * An intelligent microcode/firmware should handle
11114 11114 * this transparently at its level and not pass all
11115 11115 * the way up here.
11116 11116 *
11117 11117 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11118 11118 * or F_BSY. P_RJT is chosen to be the most appropriate
11119 11119 * at this time.
11120 11120 */
11121 11121 /* FALLTHROUGH */
11122 11122
11123 11123 default:
11124 11124 /*
11125 11125 * Just reject everything else as an invalid request.
11126 11126 */
11127 11127 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11128 11128 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11129 11129 0, KM_SLEEP, NULL);
11130 11130 if (cmd != NULL) {
11131 11131 fp_els_rjt_init(port, cmd, buf,
11132 11132 FC_ACTION_NON_RETRYABLE,
11133 11133 FC_REASON_INVALID_LINK_CTRL, job);
11134 11134
11135 11135 if (fp_sendcmd(port, cmd,
11136 11136 port->fp_fca_handle) != FC_SUCCESS) {
11137 11137 fp_free_pkt(cmd);
11138 11138 }
11139 11139 }
11140 11140 }
11141 11141 break;
11142 11142 }
11143 11143
11144 11144 mutex_enter(&port->fp_mutex);
11145 11145 ASSERT(port->fp_active_ubs > 0);
11146 11146 if (--(port->fp_active_ubs) == 0) {
11147 11147 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11148 11148 }
11149 11149 mutex_exit(&port->fp_mutex);
11150 11150 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11151 11151 1, &buf->ub_token);
11152 11152 }
11153 11153
11154 11154
11155 11155 /*
11156 11156 * Prepare a BA_RJT and send it over.
11157 11157 */
11158 11158 static void
11159 11159 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11160 11160 job_request_t *job)
11161 11161 {
11162 11162 fc_packet_t *pkt;
11163 11163 la_ba_rjt_t payload;
11164 11164
11165 11165 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11166 11166
11167 11167 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11168 11168 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11169 11169 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11170 11170 cmd->cmd_retry_count = 1;
11171 11171 cmd->cmd_ulp_pkt = NULL;
11172 11172
11173 11173 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11174 11174 cmd->cmd_job = job;
11175 11175
11176 11176 pkt = &cmd->cmd_pkt;
11177 11177
11178 11178 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11179 11179
11180 11180 payload.reserved = 0;
11181 11181 payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11182 11182 payload.explanation = FC_EXPLN_NONE;
11183 11183 payload.vendor = 0;
11184 11184
11185 11185 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11186 11186 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11187 11187 }
11188 11188
11189 11189
11190 11190 /*
11191 11191 * Prepare an LS_RJT and send it over
11192 11192 */
11193 11193 static void
11194 11194 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11195 11195 uchar_t action, uchar_t reason, job_request_t *job)
11196 11196 {
11197 11197 fc_packet_t *pkt;
11198 11198 la_els_rjt_t payload;
11199 11199
11200 11200 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11201 11201
11202 11202 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11203 11203 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11204 11204 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11205 11205 cmd->cmd_retry_count = 1;
11206 11206 cmd->cmd_ulp_pkt = NULL;
11207 11207
11208 11208 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11209 11209 cmd->cmd_job = job;
11210 11210
11211 11211 pkt = &cmd->cmd_pkt;
11212 11212
11213 11213 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11214 11214
11215 11215 payload.ls_code.ls_code = LA_ELS_RJT;
11216 11216 payload.ls_code.mbz = 0;
11217 11217 payload.action = action;
11218 11218 payload.reason = reason;
11219 11219 payload.reserved = 0;
11220 11220 payload.vu = 0;
11221 11221
11222 11222 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11223 11223 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11224 11224 }
11225 11225
11226 11226 /*
11227 11227 * Function: fp_prlo_acc_init
11228 11228 *
11229 11229 * Description: Initializes an Link Service Accept for a PRLO.
11230 11230 *
11231 11231 * Arguments: *port Local port through which the PRLO was
11232 11232 * received.
11233 11233 * cmd Command that will carry the accept.
11234 11234 * *buf Unsolicited buffer containing the PRLO
11235 11235 * request.
11236 11236 * job Job request.
11237 11237 * sleep Allocation mode.
11238 11238 *
11239 11239 * Return Value: *cmd Command containing the response.
11240 11240 *
11241 11241 * Context: Depends on the parameter sleep.
11242 11242 */
11243 11243 fp_cmd_t *
11244 11244 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11245 11245 fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11246 11246 {
11247 11247 fp_cmd_t *cmd;
11248 11248 fc_packet_t *pkt;
11249 11249 la_els_prlo_t *req;
11250 11250 size_t len;
11251 11251 uint16_t flags;
11252 11252
11253 11253 req = (la_els_prlo_t *)buf->ub_buffer;
11254 11254 len = (size_t)ntohs(req->payload_length);
11255 11255
11256 11256 /*
11257 11257 * The payload of the accept to a PRLO has to be the exact match of
11258 11258 * the payload of the request (at the exception of the code).
11259 11259 */
11260 11260 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11261 11261
11262 11262 if (cmd) {
11263 11263 /*
11264 11264 * The fp command was successfully allocated.
11265 11265 */
11266 11266 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11267 11267 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11268 11268 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11269 11269 cmd->cmd_retry_count = 1;
11270 11270 cmd->cmd_ulp_pkt = NULL;
11271 11271
11272 11272 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11273 11273 cmd->cmd_job = job;
11274 11274
11275 11275 pkt = &cmd->cmd_pkt;
11276 11276
11277 11277 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11278 11278 FC_TYPE_EXTENDED_LS);
11279 11279
11280 11280 /* The code is overwritten for the copy. */
11281 11281 req->ls_code = LA_ELS_ACC;
11282 11282 /* Response code is set. */
11283 11283 flags = ntohs(req->flags);
11284 11284 flags &= ~SP_RESP_CODE_MASK;
11285 11285 flags |= SP_RESP_CODE_REQ_EXECUTED;
11286 11286 req->flags = htons(flags);
11287 11287
11288 11288 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11289 11289 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11290 11290 }
11291 11291 return (cmd);
11292 11292 }
11293 11293
11294 11294 /*
11295 11295 * Prepare an ACC response to an ELS request
11296 11296 */
11297 11297 static void
11298 11298 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11299 11299 job_request_t *job)
11300 11300 {
11301 11301 fc_packet_t *pkt;
11302 11302 ls_code_t payload;
11303 11303
11304 11304 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11305 11305 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11306 11306 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11307 11307 cmd->cmd_retry_count = 1;
11308 11308 cmd->cmd_ulp_pkt = NULL;
11309 11309
11310 11310 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11311 11311 cmd->cmd_job = job;
11312 11312
11313 11313 pkt = &cmd->cmd_pkt;
11314 11314
11315 11315 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11316 11316
11317 11317 payload.ls_code = LA_ELS_ACC;
11318 11318 payload.mbz = 0;
11319 11319
11320 11320 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11321 11321 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11322 11322 }
11323 11323
11324 11324 /*
11325 11325 * Unsolicited PRLO handler
11326 11326 *
11327 11327 * A Process Logout should be handled by the ULP that established it. However,
11328 11328 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens
11329 11329 * when a device implicitly logs out an initiator (for whatever reason) and
11330 11330 * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11331 11331 * The logical thing to do for the device would be to send a LOGO in response
11332 11332 * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11333 11333 * a PRLO instead.
11334 11334 *
11335 11335 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11336 11336 * think that the Port Login has been lost. If we follow the Fibre Channel
11337 11337 * protocol to the letter a PRLI should be sent after accepting the PRLO. If
11338 11338 * the Port Login has also been lost, the remote port will reject the PRLI
11339 11339 * indicating that we must PLOGI first. The initiator will then turn around and
11340 11340 * send a PLOGI. The way Leadville is layered and the way the ULP interface
11341 11341 * is defined doesn't allow this scenario to be followed easily. If FCP were to
11342 11342 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11343 11343 * needed would be received by FCP. FCP would have, then, to tell the transport
11344 11344 * (fp) to PLOGI. The problem is, the transport would still think the Port
11345 11345 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11346 11346 * if you think it's not necessary". To work around that difficulty, the PRLO
11347 11347 * is treated by the transport as a LOGO. The downside to it is a Port Login
11348 11348 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11349 11349 * has nothing to do with the PRLO) may be impacted. However, this is a
11350 11350 * scenario very unlikely to happen. As of today the only ULP in Leadville
11351 11351 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be
11352 11352 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11353 11353 * unlikely).
11354 11354 */
11355 11355 static void
11356 11356 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11357 11357 fc_remote_port_t *pd, job_request_t *job)
11358 11358 {
11359 11359 int busy;
11360 11360 int rval;
11361 11361 int retain;
11362 11362 fp_cmd_t *cmd;
11363 11363 fc_portmap_t *listptr;
11364 11364 boolean_t tolerance;
11365 11365 la_els_prlo_t *req;
11366 11366
11367 11367 req = (la_els_prlo_t *)buf->ub_buffer;
11368 11368
11369 11369 if ((ntohs(req->payload_length) !=
11370 11370 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11371 11371 (req->page_length != sizeof (service_parameter_page_t))) {
11372 11372 /*
11373 11373 * We are being very restrictive. Only on page per
11374 11374 * payload. If it is not the case we reject the ELS although
11375 11375 * we should reply indicating we handle only single page
11376 11376 * per PRLO.
11377 11377 */
11378 11378 goto fp_reject_prlo;
11379 11379 }
11380 11380
11381 11381 if (ntohs(req->payload_length) > buf->ub_bufsize) {
11382 11382 /*
11383 11383 * This is in case the payload advertizes a size bigger than
11384 11384 * what it really is.
11385 11385 */
11386 11386 goto fp_reject_prlo;
11387 11387 }
11388 11388
11389 11389 mutex_enter(&port->fp_mutex);
11390 11390 busy = port->fp_statec_busy;
11391 11391 mutex_exit(&port->fp_mutex);
11392 11392
11393 11393 mutex_enter(&pd->pd_mutex);
11394 11394 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11395 11395 if (!busy) {
11396 11396 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11397 11397 pd->pd_state == PORT_DEVICE_INVALID ||
11398 11398 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11399 11399 pd->pd_type == PORT_DEVICE_OLD) {
11400 11400 busy++;
11401 11401 }
11402 11402 }
11403 11403
11404 11404 if (busy) {
11405 11405 mutex_exit(&pd->pd_mutex);
11406 11406
11407 11407 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11408 11408 "pd=%p - busy",
11409 11409 pd->pd_port_id.port_id, pd);
11410 11410
11411 11411 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11412 11412 goto fp_reject_prlo;
11413 11413 }
11414 11414 } else {
11415 11415 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11416 11416
11417 11417 if (tolerance) {
11418 11418 fctl_tc_reset(&pd->pd_logo_tc);
11419 11419 retain = 0;
11420 11420 pd->pd_state = PORT_DEVICE_INVALID;
11421 11421 }
11422 11422
11423 11423 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11424 11424 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11425 11425 tolerance, retain);
11426 11426
11427 11427 pd->pd_aux_flags |= PD_LOGGED_OUT;
11428 11428 mutex_exit(&pd->pd_mutex);
11429 11429
11430 11430 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11431 11431 if (cmd == NULL) {
11432 11432 return;
11433 11433 }
11434 11434
11435 11435 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11436 11436 if (rval != FC_SUCCESS) {
11437 11437 fp_free_pkt(cmd);
11438 11438 return;
11439 11439 }
11440 11440
11441 11441 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11442 11442
11443 11443 if (retain) {
11444 11444 fp_unregister_login(pd);
11445 11445 fctl_copy_portmap(listptr, pd);
11446 11446 } else {
11447 11447 uint32_t d_id;
11448 11448 char ww_name[17];
11449 11449
11450 11450 mutex_enter(&pd->pd_mutex);
11451 11451 d_id = pd->pd_port_id.port_id;
11452 11452 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11453 11453 mutex_exit(&pd->pd_mutex);
11454 11454
11455 11455 FP_TRACE(FP_NHEAD2(9, 0),
11456 11456 "N_x Port with D_ID=%x, PWWN=%s logged out"
11457 11457 " %d times in %d us; Giving up", d_id, ww_name,
11458 11458 FC_LOGO_TOLERANCE_LIMIT,
11459 11459 FC_LOGO_TOLERANCE_TIME_LIMIT);
11460 11460
11461 11461 fp_fillout_old_map(listptr, pd, 0);
11462 11462 listptr->map_type = PORT_DEVICE_OLD;
11463 11463 }
11464 11464
11465 11465 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11466 11466 return;
11467 11467 }
11468 11468
11469 11469 fp_reject_prlo:
11470 11470
11471 11471 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11472 11472 if (cmd != NULL) {
11473 11473 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11474 11474 FC_REASON_INVALID_LINK_CTRL, job);
11475 11475
11476 11476 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11477 11477 fp_free_pkt(cmd);
11478 11478 }
11479 11479 }
11480 11480 }
11481 11481
11482 11482 /*
11483 11483 * Unsolicited LOGO handler
11484 11484 */
11485 11485 static void
11486 11486 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11487 11487 fc_remote_port_t *pd, job_request_t *job)
11488 11488 {
11489 11489 int busy;
11490 11490 int rval;
11491 11491 int retain;
11492 11492 fp_cmd_t *cmd;
11493 11493 fc_portmap_t *listptr;
11494 11494 boolean_t tolerance;
11495 11495
11496 11496 mutex_enter(&port->fp_mutex);
11497 11497 busy = port->fp_statec_busy;
11498 11498 mutex_exit(&port->fp_mutex);
11499 11499
11500 11500 mutex_enter(&pd->pd_mutex);
11501 11501 tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11502 11502 if (!busy) {
11503 11503 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11504 11504 pd->pd_state == PORT_DEVICE_INVALID ||
11505 11505 pd->pd_flags == PD_ELS_IN_PROGRESS ||
11506 11506 pd->pd_type == PORT_DEVICE_OLD) {
11507 11507 busy++;
11508 11508 }
11509 11509 }
11510 11510
11511 11511 if (busy) {
11512 11512 mutex_exit(&pd->pd_mutex);
11513 11513
11514 11514 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11515 11515 "pd=%p - busy",
11516 11516 pd->pd_port_id.port_id, pd);
11517 11517
11518 11518 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11519 11519 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11520 11520 0, KM_SLEEP, pd);
11521 11521 if (cmd != NULL) {
11522 11522 fp_els_rjt_init(port, cmd, buf,
11523 11523 FC_ACTION_NON_RETRYABLE,
11524 11524 FC_REASON_INVALID_LINK_CTRL, job);
11525 11525
11526 11526 if (fp_sendcmd(port, cmd,
11527 11527 port->fp_fca_handle) != FC_SUCCESS) {
11528 11528 fp_free_pkt(cmd);
11529 11529 }
11530 11530 }
11531 11531 }
11532 11532 } else {
11533 11533 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11534 11534
11535 11535 if (tolerance) {
11536 11536 fctl_tc_reset(&pd->pd_logo_tc);
11537 11537 retain = 0;
11538 11538 pd->pd_state = PORT_DEVICE_INVALID;
11539 11539 }
11540 11540
11541 11541 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11542 11542 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11543 11543 tolerance, retain);
11544 11544
11545 11545 pd->pd_aux_flags |= PD_LOGGED_OUT;
11546 11546 mutex_exit(&pd->pd_mutex);
11547 11547
11548 11548 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11549 11549 KM_SLEEP, pd);
11550 11550 if (cmd == NULL) {
11551 11551 return;
11552 11552 }
11553 11553
11554 11554 fp_els_acc_init(port, cmd, buf, job);
11555 11555
11556 11556 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11557 11557 if (rval != FC_SUCCESS) {
11558 11558 fp_free_pkt(cmd);
11559 11559 return;
11560 11560 }
11561 11561
11562 11562 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11563 11563
11564 11564 if (retain) {
11565 11565 job_request_t *job;
11566 11566 fctl_ns_req_t *ns_cmd;
11567 11567
11568 11568 /*
11569 11569 * when get LOGO, first try to get PID from nameserver
11570 11570 * if failed, then we do not need
11571 11571 * send PLOGI to that remote port
11572 11572 */
11573 11573 job = fctl_alloc_job(
11574 11574 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11575 11575
11576 11576 if (job != NULL) {
11577 11577 ns_cmd = fctl_alloc_ns_cmd(
11578 11578 sizeof (ns_req_gid_pn_t),
11579 11579 sizeof (ns_resp_gid_pn_t),
11580 11580 sizeof (ns_resp_gid_pn_t),
11581 11581 0, KM_SLEEP);
11582 11582 if (ns_cmd != NULL) {
11583 11583 int ret;
11584 11584 job->job_result = FC_SUCCESS;
11585 11585 ns_cmd->ns_cmd_code = NS_GID_PN;
11586 11586 ((ns_req_gid_pn_t *)
11587 11587 (ns_cmd->ns_cmd_buf))->pwwn =
11588 11588 pd->pd_port_name;
11589 11589 ret = fp_ns_query(
11590 11590 port, ns_cmd, job, 1, KM_SLEEP);
11591 11591 if ((ret != FC_SUCCESS) ||
11592 11592 (job->job_result != FC_SUCCESS)) {
11593 11593 fctl_free_ns_cmd(ns_cmd);
11594 11594 fctl_dealloc_job(job);
11595 11595 FP_TRACE(FP_NHEAD2(9, 0),
11596 11596 "NS query failed,",
11597 11597 " delete pd");
11598 11598 goto delete_pd;
11599 11599 }
11600 11600 fctl_free_ns_cmd(ns_cmd);
11601 11601 }
11602 11602 fctl_dealloc_job(job);
11603 11603 }
11604 11604 fp_unregister_login(pd);
11605 11605 fctl_copy_portmap(listptr, pd);
11606 11606 } else {
11607 11607 uint32_t d_id;
11608 11608 char ww_name[17];
11609 11609
11610 11610 delete_pd:
11611 11611 mutex_enter(&pd->pd_mutex);
11612 11612 d_id = pd->pd_port_id.port_id;
11613 11613 fc_wwn_to_str(&pd->pd_port_name, ww_name);
11614 11614 mutex_exit(&pd->pd_mutex);
11615 11615
11616 11616 FP_TRACE(FP_NHEAD2(9, 0),
11617 11617 "N_x Port with D_ID=%x, PWWN=%s logged out"
11618 11618 " %d times in %d us; Giving up", d_id, ww_name,
11619 11619 FC_LOGO_TOLERANCE_LIMIT,
11620 11620 FC_LOGO_TOLERANCE_TIME_LIMIT);
11621 11621
11622 11622 fp_fillout_old_map(listptr, pd, 0);
11623 11623 listptr->map_type = PORT_DEVICE_OLD;
11624 11624 }
11625 11625
11626 11626 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11627 11627 }
11628 11628 }
11629 11629
11630 11630
11631 11631 /*
11632 11632 * Perform general purpose preparation of a response to an unsolicited request
11633 11633 */
11634 11634 static void
11635 11635 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11636 11636 uchar_t r_ctl, uchar_t type)
11637 11637 {
11638 11638 pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11639 11639 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11640 11640 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11641 11641 pkt->pkt_cmd_fhdr.type = type;
11642 11642 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11643 11643 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11644 11644 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl;
11645 11645 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11646 11646 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11647 11647 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11648 11648 pkt->pkt_cmd_fhdr.ro = 0;
11649 11649 pkt->pkt_cmd_fhdr.rsvd = 0;
11650 11650 pkt->pkt_comp = fp_unsol_intr;
11651 11651 pkt->pkt_timeout = FP_ELS_TIMEOUT;
11652 11652 pkt->pkt_ub_resp_token = (opaque_t)buf;
11653 11653 }
11654 11654
11655 11655 /*
11656 11656 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11657 11657 * early development days of public loop soc+ firmware, numerous problems
11658 11658 * were encountered (the details are undocumented and history now) which
11659 11659 * led to the birth of this function.
11660 11660 *
11661 11661 * If a pre-allocated unsolicited response packet is free, send out an
11662 11662 * immediate response, otherwise submit the request to the port thread
11663 11663 * to do the deferred processing.
11664 11664 */
11665 11665 static void
11666 11666 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11667 11667 {
11668 11668 int sent;
11669 11669 int f_port;
11670 11670 int do_acc;
11671 11671 fp_cmd_t *cmd;
11672 11672 la_els_logi_t *payload;
11673 11673 fc_remote_port_t *pd;
11674 11674 char dww_name[17];
11675 11675
11676 11676 ASSERT(!MUTEX_HELD(&port->fp_mutex));
11677 11677
11678 11678 cmd = port->fp_els_resp_pkt;
11679 11679
11680 11680 mutex_enter(&port->fp_mutex);
11681 11681 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11682 11682 mutex_exit(&port->fp_mutex);
11683 11683
11684 11684 switch (buf->ub_buffer[0]) {
11685 11685 case LA_ELS_PLOGI: {
11686 11686 int small;
11687 11687
11688 11688 payload = (la_els_logi_t *)buf->ub_buffer;
11689 11689
11690 11690 f_port = FP_IS_F_PORT(payload->
11691 11691 common_service.cmn_features) ? 1 : 0;
11692 11692
11693 11693 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11694 11694 &payload->nport_ww_name);
11695 11695 pd = fctl_get_remote_port_by_pwwn(port,
11696 11696 &payload->nport_ww_name);
11697 11697 if (pd) {
11698 11698 mutex_enter(&pd->pd_mutex);
11699 11699 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11700 11700 /*
11701 11701 * Most likely this means a cross login is in
11702 11702 * progress or a device about to be yanked out.
11703 11703 * Only accept the plogi if my wwn is smaller.
11704 11704 */
11705 11705 if (pd->pd_type == PORT_DEVICE_OLD) {
11706 11706 sent = 1;
11707 11707 }
11708 11708 /*
11709 11709 * Stop plogi request (if any)
11710 11710 * attempt from local side to speedup
11711 11711 * the discovery progress.
11712 11712 * Mark the pd as PD_PLOGI_RECEPIENT.
11713 11713 */
11714 11714 if (f_port == 0 && small < 0) {
11715 11715 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11716 11716 }
11717 11717 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11718 11718
11719 11719 mutex_exit(&pd->pd_mutex);
11720 11720
11721 11721 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11722 11722 "Unsol PLOGI received. PD still exists in the "
11723 11723 "PWWN list. pd=%p PWWN=%s, sent=%x",
11724 11724 pd, dww_name, sent);
11725 11725
11726 11726 if (f_port == 0 && small < 0) {
11727 11727 FP_TRACE(FP_NHEAD1(3, 0),
11728 11728 "fp_i_handle_unsol_els: Mark the pd"
11729 11729 " as plogi recipient, pd=%p, PWWN=%s"
11730 11730 ", sent=%x",
11731 11731 pd, dww_name, sent);
11732 11732 }
11733 11733 } else {
11734 11734 sent = 0;
11735 11735 }
11736 11736
11737 11737 /*
11738 11738 * To avoid Login collisions, accept only if my WWN
11739 11739 * is smaller than the requester (A curious side note
11740 11740 * would be that this rule may not satisfy the PLOGIs
11741 11741 * initiated by the switch from not-so-well known
11742 11742 * ports such as 0xFFFC41)
11743 11743 */
11744 11744 if ((f_port == 0 && small < 0) ||
11745 11745 (((small > 0 && do_acc) ||
11746 11746 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11747 11747 if (fp_is_class_supported(port->fp_cos,
11748 11748 buf->ub_class) == FC_FAILURE) {
11749 11749 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11750 11750 cmd->cmd_pkt.pkt_cmdlen =
11751 11751 sizeof (la_els_rjt_t);
11752 11752 cmd->cmd_pkt.pkt_rsplen = 0;
11753 11753 fp_els_rjt_init(port, cmd, buf,
11754 11754 FC_ACTION_NON_RETRYABLE,
11755 11755 FC_REASON_CLASS_NOT_SUPP, NULL);
11756 11756 FP_TRACE(FP_NHEAD1(3, 0),
11757 11757 "fp_i_handle_unsol_els: "
11758 11758 "Unsupported class. "
11759 11759 "Rejecting PLOGI");
11760 11760
11761 11761 } else {
11762 11762 mutex_enter(&port->fp_mutex);
11763 11763 port->fp_els_resp_pkt_busy = 0;
11764 11764 mutex_exit(&port->fp_mutex);
11765 11765 return;
11766 11766 }
11767 11767 } else {
11768 11768 cmd->cmd_pkt.pkt_cmdlen =
11769 11769 sizeof (la_els_logi_t);
11770 11770 cmd->cmd_pkt.pkt_rsplen = 0;
11771 11771
11772 11772 /*
11773 11773 * If fp_port_id is zero and topology is
11774 11774 * Point-to-Point, get the local port id from
11775 11775 * the d_id in the PLOGI request.
11776 11776 * If the outgoing FLOGI hasn't been accepted,
11777 11777 * the topology will be unknown here. But it's
11778 11778 * still safe to save the d_id to fp_port_id,
11779 11779 * just because it will be overwritten later
11780 11780 * if the topology is not Point-to-Point.
11781 11781 */
11782 11782 mutex_enter(&port->fp_mutex);
11783 11783 if ((port->fp_port_id.port_id == 0) &&
11784 11784 (port->fp_topology == FC_TOP_PT_PT ||
11785 11785 port->fp_topology == FC_TOP_UNKNOWN)) {
11786 11786 port->fp_port_id.port_id =
11787 11787 buf->ub_frame.d_id;
11788 11788 }
11789 11789 mutex_exit(&port->fp_mutex);
11790 11790
11791 11791 /*
11792 11792 * Sometime later, we should validate
11793 11793 * the service parameters instead of
11794 11794 * just accepting it.
11795 11795 */
11796 11796 fp_login_acc_init(port, cmd, buf, NULL,
11797 11797 KM_NOSLEEP);
11798 11798 FP_TRACE(FP_NHEAD1(3, 0),
11799 11799 "fp_i_handle_unsol_els: Accepting PLOGI,"
11800 11800 " f_port=%d, small=%d, do_acc=%d,"
11801 11801 " sent=%d.", f_port, small, do_acc,
11802 11802 sent);
11803 11803 }
11804 11804 } else {
11805 11805 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11806 11806 port->fp_options & FP_SEND_RJT) {
11807 11807 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11808 11808 cmd->cmd_pkt.pkt_rsplen = 0;
11809 11809 fp_els_rjt_init(port, cmd, buf,
11810 11810 FC_ACTION_NON_RETRYABLE,
11811 11811 FC_REASON_LOGICAL_BSY, NULL);
11812 11812 FP_TRACE(FP_NHEAD1(3, 0),
11813 11813 "fp_i_handle_unsol_els: "
11814 11814 "Rejecting PLOGI with Logical Busy."
11815 11815 "Possible Login collision.");
11816 11816 } else {
11817 11817 mutex_enter(&port->fp_mutex);
11818 11818 port->fp_els_resp_pkt_busy = 0;
11819 11819 mutex_exit(&port->fp_mutex);
11820 11820 return;
11821 11821 }
11822 11822 }
11823 11823 break;
11824 11824 }
11825 11825
11826 11826 case LA_ELS_FLOGI:
11827 11827 if (fp_is_class_supported(port->fp_cos,
11828 11828 buf->ub_class) == FC_FAILURE) {
11829 11829 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11830 11830 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11831 11831 cmd->cmd_pkt.pkt_rsplen = 0;
11832 11832 fp_els_rjt_init(port, cmd, buf,
11833 11833 FC_ACTION_NON_RETRYABLE,
11834 11834 FC_REASON_CLASS_NOT_SUPP, NULL);
11835 11835 FP_TRACE(FP_NHEAD1(3, 0),
11836 11836 "fp_i_handle_unsol_els: "
11837 11837 "Unsupported Class. Rejecting FLOGI.");
11838 11838 } else {
11839 11839 mutex_enter(&port->fp_mutex);
11840 11840 port->fp_els_resp_pkt_busy = 0;
11841 11841 mutex_exit(&port->fp_mutex);
11842 11842 return;
11843 11843 }
11844 11844 } else {
11845 11845 mutex_enter(&port->fp_mutex);
11846 11846 if (FC_PORT_STATE_MASK(port->fp_state) !=
11847 11847 FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11848 11848 buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11849 11849 mutex_exit(&port->fp_mutex);
11850 11850 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11851 11851 cmd->cmd_pkt.pkt_cmdlen =
11852 11852 sizeof (la_els_rjt_t);
11853 11853 cmd->cmd_pkt.pkt_rsplen = 0;
11854 11854 fp_els_rjt_init(port, cmd, buf,
11855 11855 FC_ACTION_NON_RETRYABLE,
11856 11856 FC_REASON_INVALID_LINK_CTRL,
11857 11857 NULL);
11858 11858 FP_TRACE(FP_NHEAD1(3, 0),
11859 11859 "fp_i_handle_unsol_els: "
11860 11860 "Invalid Link Ctrl. "
11861 11861 "Rejecting FLOGI.");
11862 11862 } else {
11863 11863 mutex_enter(&port->fp_mutex);
11864 11864 port->fp_els_resp_pkt_busy = 0;
11865 11865 mutex_exit(&port->fp_mutex);
11866 11866 return;
11867 11867 }
11868 11868 } else {
11869 11869 mutex_exit(&port->fp_mutex);
11870 11870 cmd->cmd_pkt.pkt_cmdlen =
11871 11871 sizeof (la_els_logi_t);
11872 11872 cmd->cmd_pkt.pkt_rsplen = 0;
11873 11873 /*
11874 11874 * Let's not aggressively validate the N_Port's
11875 11875 * service parameters until PLOGI. Suffice it
11876 11876 * to give a hint that we are an N_Port and we
11877 11877 * are game to some serious stuff here.
11878 11878 */
11879 11879 fp_login_acc_init(port, cmd, buf,
11880 11880 NULL, KM_NOSLEEP);
11881 11881 FP_TRACE(FP_NHEAD1(3, 0),
11882 11882 "fp_i_handle_unsol_els: "
11883 11883 "Accepting FLOGI.");
11884 11884 }
11885 11885 }
11886 11886 break;
11887 11887
11888 11888 default:
11889 11889 return;
11890 11890 }
11891 11891
11892 11892 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11893 11893 mutex_enter(&port->fp_mutex);
11894 11894 port->fp_els_resp_pkt_busy = 0;
11895 11895 mutex_exit(&port->fp_mutex);
11896 11896 }
11897 11897 }
11898 11898
11899 11899
11900 11900 /*
11901 11901 * Handle unsolicited PLOGI request
11902 11902 */
11903 11903 static void
11904 11904 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11905 11905 job_request_t *job, int sleep)
11906 11906 {
11907 11907 int sent;
11908 11908 int small;
11909 11909 int f_port;
11910 11910 int do_acc;
11911 11911 fp_cmd_t *cmd;
11912 11912 la_wwn_t *swwn;
11913 11913 la_wwn_t *dwwn;
11914 11914 la_els_logi_t *payload;
11915 11915 fc_remote_port_t *pd;
11916 11916 char dww_name[17];
11917 11917
11918 11918 payload = (la_els_logi_t *)buf->ub_buffer;
11919 11919 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11920 11920
11921 11921 mutex_enter(&port->fp_mutex);
11922 11922 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11923 11923 mutex_exit(&port->fp_mutex);
11924 11924
11925 11925 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11926 11926 "type=%x, f_ctl=%x"
11927 11927 " seq_id=%x, ox_id=%x, rx_id=%x"
11928 11928 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11929 11929 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11930 11930 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11931 11931
11932 11932 swwn = &port->fp_service_params.nport_ww_name;
11933 11933 dwwn = &payload->nport_ww_name;
11934 11934 small = fctl_wwn_cmp(swwn, dwwn);
11935 11935 pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11936 11936 if (pd) {
11937 11937 mutex_enter(&pd->pd_mutex);
11938 11938 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11939 11939 /*
11940 11940 * Most likely this means a cross login is in
11941 11941 * progress or a device about to be yanked out.
11942 11942 * Only accept the plogi if my wwn is smaller.
11943 11943 */
11944 11944
11945 11945 if (pd->pd_type == PORT_DEVICE_OLD) {
11946 11946 sent = 1;
11947 11947 }
11948 11948 /*
11949 11949 * Stop plogi request (if any)
11950 11950 * attempt from local side to speedup
11951 11951 * the discovery progress.
11952 11952 * Mark the pd as PD_PLOGI_RECEPIENT.
11953 11953 */
11954 11954 if (f_port == 0 && small < 0) {
11955 11955 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11956 11956 }
11957 11957 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11958 11958
11959 11959 mutex_exit(&pd->pd_mutex);
11960 11960
11961 11961 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11962 11962 " received. PD still exists in the PWWN list. pd=%p "
11963 11963 "PWWN=%s, sent=%x", pd, dww_name, sent);
11964 11964
11965 11965 if (f_port == 0 && small < 0) {
11966 11966 FP_TRACE(FP_NHEAD1(3, 0),
11967 11967 "fp_handle_unsol_plogi: Mark the pd"
11968 11968 " as plogi recipient, pd=%p, PWWN=%s"
11969 11969 ", sent=%x",
11970 11970 pd, dww_name, sent);
11971 11971 }
11972 11972 } else {
11973 11973 sent = 0;
11974 11974 }
11975 11975
11976 11976 /*
11977 11977 * Avoid Login collisions by accepting only if my WWN is smaller.
11978 11978 *
11979 11979 * A side note: There is no need to start a PLOGI from this end in
11980 11980 * this context if login isn't going to be accepted for the
11981 11981 * above reason as either a LIP (in private loop), RSCN (in
11982 11982 * fabric topology), or an FLOGI (in point to point - Huh ?
11983 11983 * check FC-PH) would normally drive the PLOGI from this end.
11984 11984 * At this point of time there is no need for an inbound PLOGI
11985 11985 * to kick an outbound PLOGI when it is going to be rejected
11986 11986 * for the reason of WWN being smaller. However it isn't hard
11987 11987 * to do that either (when such a need arises, start a timer
11988 11988 * for a duration that extends beyond a normal device discovery
11989 11989 * time and check if an outbound PLOGI did go before that, if
11990 11990 * none fire one)
11991 11991 *
11992 11992 * Unfortunately, as it turned out, during booting, it is possible
11993 11993 * to miss another initiator in the same loop as port driver
11994 11994 * instances are serially attached. While preserving the above
11995 11995 * comments for belly laughs, please kick an outbound PLOGI in
11996 11996 * a non-switch environment (which is a pt pt between N_Ports or
11997 11997 * a private loop)
11998 11998 *
11999 11999 * While preserving the above comments for amusement, send an
12000 12000 * ACC if the PLOGI is going to be rejected for WWN being smaller
12001 12001 * when no discovery is in progress at this end. Turn around
12002 12002 * and make the port device as the PLOGI initiator, so that
12003 12003 * during subsequent link/loop initialization, this end drives
12004 12004 * the PLOGI (In fact both ends do in this particular case, but
12005 12005 * only one wins)
12006 12006 *
12007 12007 * Make sure the PLOGIs initiated by the switch from not-so-well-known
12008 12008 * ports (such as 0xFFFC41) are accepted too.
12009 12009 */
12010 12010 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
12011 12011 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
12012 12012 if (fp_is_class_supported(port->fp_cos,
12013 12013 buf->ub_class) == FC_FAILURE) {
12014 12014 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12015 12015 cmd = fp_alloc_pkt(port,
12016 12016 sizeof (la_els_logi_t), 0, sleep, pd);
12017 12017 if (cmd == NULL) {
12018 12018 return;
12019 12019 }
12020 12020 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12021 12021 cmd->cmd_pkt.pkt_rsplen = 0;
12022 12022 fp_els_rjt_init(port, cmd, buf,
12023 12023 FC_ACTION_NON_RETRYABLE,
12024 12024 FC_REASON_CLASS_NOT_SUPP, job);
12025 12025 FP_TRACE(FP_NHEAD1(3, 0),
12026 12026 "fp_handle_unsol_plogi: "
12027 12027 "Unsupported class. rejecting PLOGI");
12028 12028 }
12029 12029 } else {
12030 12030 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12031 12031 0, sleep, pd);
12032 12032 if (cmd == NULL) {
12033 12033 return;
12034 12034 }
12035 12035 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
12036 12036 cmd->cmd_pkt.pkt_rsplen = 0;
12037 12037
12038 12038 /*
12039 12039 * Sometime later, we should validate the service
12040 12040 * parameters instead of just accepting it.
12041 12041 */
12042 12042 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12043 12043 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12044 12044 "Accepting PLOGI, f_port=%d, small=%d, "
12045 12045 "do_acc=%d, sent=%d.", f_port, small, do_acc,
12046 12046 sent);
12047 12047
12048 12048 /*
12049 12049 * If fp_port_id is zero and topology is
12050 12050 * Point-to-Point, get the local port id from
12051 12051 * the d_id in the PLOGI request.
12052 12052 * If the outgoing FLOGI hasn't been accepted,
12053 12053 * the topology will be unknown here. But it's
12054 12054 * still safe to save the d_id to fp_port_id,
12055 12055 * just because it will be overwritten later
12056 12056 * if the topology is not Point-to-Point.
12057 12057 */
12058 12058 mutex_enter(&port->fp_mutex);
12059 12059 if ((port->fp_port_id.port_id == 0) &&
12060 12060 (port->fp_topology == FC_TOP_PT_PT ||
12061 12061 port->fp_topology == FC_TOP_UNKNOWN)) {
12062 12062 port->fp_port_id.port_id =
12063 12063 buf->ub_frame.d_id;
12064 12064 }
12065 12065 mutex_exit(&port->fp_mutex);
12066 12066 }
12067 12067 } else {
12068 12068 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12069 12069 port->fp_options & FP_SEND_RJT) {
12070 12070 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12071 12071 0, sleep, pd);
12072 12072 if (cmd == NULL) {
12073 12073 return;
12074 12074 }
12075 12075 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12076 12076 cmd->cmd_pkt.pkt_rsplen = 0;
12077 12077 /*
12078 12078 * Send out Logical busy to indicate
12079 12079 * the detection of PLOGI collision
12080 12080 */
12081 12081 fp_els_rjt_init(port, cmd, buf,
12082 12082 FC_ACTION_NON_RETRYABLE,
12083 12083 FC_REASON_LOGICAL_BSY, job);
12084 12084
12085 12085 fc_wwn_to_str(dwwn, dww_name);
12086 12086 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12087 12087 "Rejecting Unsol PLOGI with Logical Busy."
12088 12088 "possible PLOGI collision. PWWN=%s, sent=%x",
12089 12089 dww_name, sent);
12090 12090 } else {
12091 12091 return;
12092 12092 }
12093 12093 }
12094 12094
12095 12095 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12096 12096 fp_free_pkt(cmd);
12097 12097 }
12098 12098 }
12099 12099
12100 12100
12101 12101 /*
12102 12102 * Handle mischievous turning over of our own FLOGI requests back to
12103 12103 * us by the SOC+ microcode. In other words, look at the class of such
12104 12104 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12105 12105 * on the floor
12106 12106 */
12107 12107 static void
12108 12108 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12109 12109 job_request_t *job, int sleep)
12110 12110 {
12111 12111 uint32_t state;
12112 12112 uint32_t s_id;
12113 12113 fp_cmd_t *cmd;
12114 12114
12115 12115 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12116 12116 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12117 12117 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12118 12118 0, sleep, NULL);
12119 12119 if (cmd == NULL) {
12120 12120 return;
12121 12121 }
12122 12122 fp_els_rjt_init(port, cmd, buf,
12123 12123 FC_ACTION_NON_RETRYABLE,
12124 12124 FC_REASON_CLASS_NOT_SUPP, job);
12125 12125 } else {
12126 12126 return;
12127 12127 }
12128 12128 } else {
12129 12129
12130 12130 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12131 12131 " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12132 12132 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12133 12133 buf->ub_frame.s_id, buf->ub_frame.d_id,
12134 12134 buf->ub_frame.type, buf->ub_frame.f_ctl,
12135 12135 buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12136 12136 buf->ub_frame.rx_id, buf->ub_frame.ro);
12137 12137
12138 12138 mutex_enter(&port->fp_mutex);
12139 12139 state = FC_PORT_STATE_MASK(port->fp_state);
12140 12140 s_id = port->fp_port_id.port_id;
12141 12141 mutex_exit(&port->fp_mutex);
12142 12142
12143 12143 if (state != FC_STATE_ONLINE ||
12144 12144 (s_id && buf->ub_frame.s_id == s_id)) {
12145 12145 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12146 12146 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12147 12147 0, sleep, NULL);
12148 12148 if (cmd == NULL) {
12149 12149 return;
12150 12150 }
12151 12151 fp_els_rjt_init(port, cmd, buf,
12152 12152 FC_ACTION_NON_RETRYABLE,
12153 12153 FC_REASON_INVALID_LINK_CTRL, job);
12154 12154 FP_TRACE(FP_NHEAD1(3, 0),
12155 12155 "fp_handle_unsol_flogi: "
12156 12156 "Rejecting PLOGI. Invalid Link CTRL");
12157 12157 } else {
12158 12158 return;
12159 12159 }
12160 12160 } else {
12161 12161 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12162 12162 0, sleep, NULL);
12163 12163 if (cmd == NULL) {
12164 12164 return;
12165 12165 }
12166 12166 /*
12167 12167 * Let's not aggressively validate the N_Port's
12168 12168 * service parameters until PLOGI. Suffice it
12169 12169 * to give a hint that we are an N_Port and we
12170 12170 * are game to some serious stuff here.
12171 12171 */
12172 12172 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12173 12173 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12174 12174 "Accepting PLOGI");
12175 12175 }
12176 12176 }
12177 12177
12178 12178 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12179 12179 fp_free_pkt(cmd);
12180 12180 }
12181 12181 }
12182 12182
12183 12183
12184 12184 /*
12185 12185 * Perform PLOGI accept
12186 12186 */
12187 12187 static void
12188 12188 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12189 12189 job_request_t *job, int sleep)
12190 12190 {
12191 12191 fc_packet_t *pkt;
12192 12192 fc_portmap_t *listptr;
12193 12193 la_els_logi_t payload;
12194 12194
12195 12195 ASSERT(buf != NULL);
12196 12196
12197 12197 /*
12198 12198 * If we are sending ACC to PLOGI and we haven't already
12199 12199 * create port and node device handles, let's create them
12200 12200 * here.
12201 12201 */
12202 12202 if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12203 12203 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12204 12204 int small;
12205 12205 int do_acc;
12206 12206 fc_remote_port_t *pd;
12207 12207 la_els_logi_t *req;
12208 12208
12209 12209 req = (la_els_logi_t *)buf->ub_buffer;
12210 12210 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12211 12211 &req->nport_ww_name);
12212 12212
12213 12213 mutex_enter(&port->fp_mutex);
12214 12214 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12215 12215 mutex_exit(&port->fp_mutex);
12216 12216
12217 12217 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12218 12218 port->fp_port_id.port_id, buf->ub_frame.s_id);
12219 12219 pd = fctl_create_remote_port(port, &req->node_ww_name,
12220 12220 &req->nport_ww_name, buf->ub_frame.s_id,
12221 12221 PD_PLOGI_RECEPIENT, sleep);
12222 12222 if (pd == NULL) {
12223 12223 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12224 12224 "Couldn't create port device for d_id:0x%x",
12225 12225 buf->ub_frame.s_id);
12226 12226
12227 12227 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12228 12228 "couldn't create port device d_id=%x",
12229 12229 buf->ub_frame.s_id);
12230 12230 } else {
12231 12231 /*
12232 12232 * usoc currently returns PLOGIs inline and
12233 12233 * the maximum buffer size is 60 bytes or so.
12234 12234 * So attempt not to look beyond what is in
12235 12235 * the unsolicited buffer
12236 12236 *
12237 12237 * JNI also traverses this path sometimes
12238 12238 */
12239 12239 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12240 12240 fp_register_login(NULL, pd, req, buf->ub_class);
12241 12241 } else {
12242 12242 mutex_enter(&pd->pd_mutex);
12243 12243 if (pd->pd_login_count == 0) {
12244 12244 pd->pd_login_count++;
12245 12245 }
12246 12246 pd->pd_state = PORT_DEVICE_LOGGED_IN;
12247 12247 pd->pd_login_class = buf->ub_class;
12248 12248 mutex_exit(&pd->pd_mutex);
12249 12249 }
12250 12250
12251 12251 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12252 12252 if (listptr != NULL) {
12253 12253 fctl_copy_portmap(listptr, pd);
12254 12254 (void) fp_ulp_devc_cb(port, listptr,
12255 12255 1, 1, sleep, 0);
12256 12256 }
12257 12257
12258 12258 if (small > 0 && do_acc) {
12259 12259 mutex_enter(&pd->pd_mutex);
12260 12260 pd->pd_recepient = PD_PLOGI_INITIATOR;
12261 12261 mutex_exit(&pd->pd_mutex);
12262 12262 }
12263 12263 }
12264 12264 }
12265 12265
12266 12266 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12267 12267 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12268 12268 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12269 12269 cmd->cmd_retry_count = 1;
12270 12270 cmd->cmd_ulp_pkt = NULL;
12271 12271
12272 12272 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12273 12273 cmd->cmd_job = job;
12274 12274
12275 12275 pkt = &cmd->cmd_pkt;
12276 12276
12277 12277 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12278 12278
12279 12279 payload = port->fp_service_params;
12280 12280 payload.ls_code.ls_code = LA_ELS_ACC;
12281 12281
12282 12282 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12283 12283 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12284 12284
12285 12285 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12286 12286 "bufsize:0x%x sizeof (la_els_logi):0x%x "
12287 12287 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12288 12288 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12289 12289 buf->ub_bufsize, sizeof (la_els_logi_t),
12290 12290 port->fp_service_params.nport_ww_name.w.naa_id,
12291 12291 port->fp_service_params.nport_ww_name.w.nport_id,
12292 12292 port->fp_service_params.nport_ww_name.w.wwn_hi,
12293 12293 port->fp_service_params.nport_ww_name.w.wwn_lo,
12294 12294 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12295 12295 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12296 12296 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12297 12297 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12298 12298 port->fp_statec_busy);
12299 12299 }
12300 12300
12301 12301
12302 12302 #define RSCN_EVENT_NAME_LEN 256
12303 12303
12304 12304 /*
12305 12305 * Handle RSCNs
12306 12306 */
12307 12307 static void
12308 12308 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12309 12309 job_request_t *job, int sleep)
12310 12310 {
12311 12311 uint32_t mask;
12312 12312 fp_cmd_t *cmd;
12313 12313 uint32_t count;
12314 12314 int listindex;
12315 12315 int16_t len;
12316 12316 fc_rscn_t *payload;
12317 12317 fc_portmap_t *listptr;
12318 12318 fctl_ns_req_t *ns_cmd;
12319 12319 fc_affected_id_t *page;
12320 12320 caddr_t nvname;
12321 12321 nvlist_t *attr_list = NULL;
12322 12322
12323 12323 mutex_enter(&port->fp_mutex);
12324 12324 if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12325 12325 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12326 12326 --port->fp_rscn_count;
12327 12327 }
12328 12328 mutex_exit(&port->fp_mutex);
12329 12329 return;
12330 12330 }
12331 12331 mutex_exit(&port->fp_mutex);
12332 12332
12333 12333 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12334 12334 if (cmd != NULL) {
12335 12335 fp_els_acc_init(port, cmd, buf, job);
12336 12336 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12337 12337 fp_free_pkt(cmd);
12338 12338 }
12339 12339 }
12340 12340
12341 12341 payload = (fc_rscn_t *)buf->ub_buffer;
12342 12342 ASSERT(payload->rscn_code == LA_ELS_RSCN);
12343 12343 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12344 12344
12345 12345 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12346 12346
12347 12347 if (len <= 0) {
12348 12348 mutex_enter(&port->fp_mutex);
12349 12349 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12350 12350 --port->fp_rscn_count;
12351 12351 }
12352 12352 mutex_exit(&port->fp_mutex);
12353 12353
12354 12354 return;
12355 12355 }
12356 12356
12357 12357 ASSERT((len & 0x3) == 0); /* Must be power of 4 */
12358 12358 count = (len >> 2) << 1; /* number of pages multiplied by 2 */
12359 12359
12360 12360 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12361 12361 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12362 12362
12363 12363 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12364 12364
12365 12365 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12366 12366 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12367 12367 0, sleep);
12368 12368 if (ns_cmd == NULL) {
12369 12369 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12370 12370
12371 12371 mutex_enter(&port->fp_mutex);
12372 12372 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12373 12373 --port->fp_rscn_count;
12374 12374 }
12375 12375 mutex_exit(&port->fp_mutex);
12376 12376
12377 12377 return;
12378 12378 }
12379 12379
12380 12380 ns_cmd->ns_cmd_code = NS_GPN_ID;
12381 12381
12382 12382 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12383 12383 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12384 12384 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12385 12385 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12386 12386 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12387 12387
12388 12388 /* Only proceed if we can allocate nvname and the nvlist */
12389 12389 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12390 12390 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12391 12391 KM_NOSLEEP) == DDI_SUCCESS) {
12392 12392 if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12393 12393 port->fp_instance) == DDI_SUCCESS &&
12394 12394 nvlist_add_byte_array(attr_list, "port-wwn",
12395 12395 port->fp_service_params.nport_ww_name.raw_wwn,
12396 12396 sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12397 12397 nvlist_free(attr_list);
12398 12398 attr_list = NULL;
12399 12399 }
12400 12400 }
12401 12401
12402 12402 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12403 12403 /* Add affected page to the event payload */
12404 12404 if (attr_list != NULL) {
12405 12405 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12406 12406 "affected_page_%d", listindex);
12407 12407 if (attr_list && nvlist_add_uint32(attr_list, nvname,
12408 12408 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12409 12409 /* We don't send a partial event, so dump it */
12410 12410 nvlist_free(attr_list);
12411 12411 attr_list = NULL;
12412 12412 }
12413 12413 }
12414 12414 /*
12415 12415 * Query the NS to get the Port WWN for this
12416 12416 * affected D_ID.
12417 12417 */
12418 12418 mask = 0;
12419 12419 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12420 12420 case FC_RSCN_PORT_ADDRESS:
12421 12421 fp_validate_rscn_page(port, page, job, ns_cmd,
12422 12422 listptr, &listindex, sleep);
12423 12423
12424 12424 if (listindex == 0) {
12425 12425 /*
12426 12426 * We essentially did not process this RSCN. So,
12427 12427 * ULPs are not going to be called and so we
12428 12428 * decrement the rscn_count
12429 12429 */
12430 12430 mutex_enter(&port->fp_mutex);
12431 12431 if (--port->fp_rscn_count ==
12432 12432 FC_INVALID_RSCN_COUNT) {
12433 12433 --port->fp_rscn_count;
12434 12434 }
12435 12435 mutex_exit(&port->fp_mutex);
12436 12436 }
12437 12437 break;
12438 12438
12439 12439 case FC_RSCN_AREA_ADDRESS:
12440 12440 mask = 0xFFFF00;
12441 12441 /* FALLTHROUGH */
12442 12442
12443 12443 case FC_RSCN_DOMAIN_ADDRESS:
12444 12444 if (!mask) {
12445 12445 mask = 0xFF0000;
12446 12446 }
12447 12447 fp_validate_area_domain(port, page->aff_d_id, mask,
12448 12448 job, sleep);
12449 12449 break;
12450 12450
12451 12451 case FC_RSCN_FABRIC_ADDRESS:
12452 12452 /*
12453 12453 * We need to discover all the devices on this
12454 12454 * port.
12455 12455 */
12456 12456 fp_validate_area_domain(port, 0, 0, job, sleep);
12457 12457 break;
12458 12458
12459 12459 default:
12460 12460 break;
12461 12461 }
12462 12462 }
12463 12463 if (attr_list != NULL) {
12464 12464 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12465 12465 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12466 12466 NULL, DDI_SLEEP);
12467 12467 nvlist_free(attr_list);
12468 12468 } else {
12469 12469 FP_TRACE(FP_NHEAD1(9, 0),
12470 12470 "RSCN handled, but event not sent to userland");
12471 12471 }
12472 12472 if (nvname != NULL) {
12473 12473 kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12474 12474 }
12475 12475
12476 12476 if (ns_cmd) {
12477 12477 fctl_free_ns_cmd(ns_cmd);
12478 12478 }
12479 12479
12480 12480 if (listindex) {
12481 12481 #ifdef DEBUG
12482 12482 page = (fc_affected_id_t *)(buf->ub_buffer +
12483 12483 sizeof (fc_rscn_t));
12484 12484
12485 12485 if (listptr->map_did.port_id != page->aff_d_id) {
12486 12486 FP_TRACE(FP_NHEAD1(9, 0),
12487 12487 "PORT RSCN: processed=%x, reporting=%x",
12488 12488 listptr->map_did.port_id, page->aff_d_id);
12489 12489 }
12490 12490 #endif
12491 12491
12492 12492 (void) fp_ulp_devc_cb(port, listptr, listindex, count,
12493 12493 sleep, 0);
12494 12494 } else {
12495 12495 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12496 12496 }
12497 12497 }
12498 12498
12499 12499
12500 12500 /*
12501 12501 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12502 12502 */
12503 12503 static void
12504 12504 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12505 12505 {
12506 12506 int is_switch;
12507 12507 int initiator;
12508 12508 fc_local_port_t *port;
12509 12509
12510 12510 port = pd->pd_port;
12511 12511
12512 12512 /* This function has the following bunch of assumptions */
12513 12513 ASSERT(port != NULL);
12514 12514 ASSERT(MUTEX_HELD(&port->fp_mutex));
12515 12515 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12516 12516 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12517 12517
12518 12518 pd->pd_state = PORT_DEVICE_INVALID;
12519 12519 pd->pd_type = PORT_DEVICE_OLD;
12520 12520 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12521 12521 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12522 12522
12523 12523 fctl_delist_did_table(port, pd);
12524 12524 fctl_delist_pwwn_table(port, pd);
12525 12525
12526 12526 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12527 12527 " removed the PD=%p from DID and PWWN tables",
12528 12528 port, pd->pd_port_id.port_id, pd);
12529 12529
12530 12530 if ((!flag) && port && initiator && is_switch) {
12531 12531 (void) fctl_add_orphan_held(port, pd);
12532 12532 }
12533 12533 fctl_copy_portmap_held(map, pd);
12534 12534 map->map_pd = pd;
12535 12535 }
12536 12536
12537 12537 /*
12538 12538 * Fill out old map for ULPs
12539 12539 */
12540 12540 static void
12541 12541 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12542 12542 {
12543 12543 int is_switch;
12544 12544 int initiator;
12545 12545 fc_local_port_t *port;
12546 12546
12547 12547 mutex_enter(&pd->pd_mutex);
12548 12548 port = pd->pd_port;
12549 12549 mutex_exit(&pd->pd_mutex);
12550 12550
12551 12551 mutex_enter(&port->fp_mutex);
12552 12552 mutex_enter(&pd->pd_mutex);
12553 12553
12554 12554 pd->pd_state = PORT_DEVICE_INVALID;
12555 12555 pd->pd_type = PORT_DEVICE_OLD;
12556 12556 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12557 12557 is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12558 12558
12559 12559 fctl_delist_did_table(port, pd);
12560 12560 fctl_delist_pwwn_table(port, pd);
12561 12561
12562 12562 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12563 12563 " removed the PD=%p from DID and PWWN tables",
12564 12564 port, pd->pd_port_id.port_id, pd);
12565 12565
12566 12566 mutex_exit(&pd->pd_mutex);
12567 12567 mutex_exit(&port->fp_mutex);
12568 12568
12569 12569 ASSERT(port != NULL);
12570 12570 if ((!flag) && port && initiator && is_switch) {
12571 12571 (void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12572 12572 }
12573 12573 fctl_copy_portmap(map, pd);
12574 12574 map->map_pd = pd;
12575 12575 }
12576 12576
12577 12577
12578 12578 /*
12579 12579 * Fillout Changed Map for ULPs
12580 12580 */
12581 12581 static void
12582 12582 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12583 12583 uint32_t *new_did, la_wwn_t *new_pwwn)
12584 12584 {
12585 12585 ASSERT(MUTEX_HELD(&pd->pd_mutex));
12586 12586
12587 12587 pd->pd_type = PORT_DEVICE_CHANGED;
12588 12588 if (new_did) {
12589 12589 pd->pd_port_id.port_id = *new_did;
12590 12590 }
12591 12591 if (new_pwwn) {
12592 12592 pd->pd_port_name = *new_pwwn;
12593 12593 }
12594 12594 mutex_exit(&pd->pd_mutex);
12595 12595
12596 12596 fctl_copy_portmap(map, pd);
12597 12597
12598 12598 mutex_enter(&pd->pd_mutex);
12599 12599 pd->pd_type = PORT_DEVICE_NOCHANGE;
12600 12600 }
12601 12601
12602 12602
12603 12603 /*
12604 12604 * Fillout New Name Server map
12605 12605 */
12606 12606 static void
12607 12607 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12608 12608 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12609 12609 {
12610 12610 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12611 12611
12612 12612 if (handle) {
12613 12613 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12614 12614 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12615 12615 DDI_DEV_AUTOINCR);
12616 12616 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12617 12617 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12618 12618 DDI_DEV_AUTOINCR);
12619 12619 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12620 12620 (uint8_t *)gan_resp->gan_fc4types,
12621 12621 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12622 12622 } else {
12623 12623 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12624 12624 sizeof (gan_resp->gan_pwwn));
12625 12625 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12626 12626 sizeof (gan_resp->gan_nwwn));
12627 12627 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12628 12628 sizeof (gan_resp->gan_fc4types));
12629 12629 }
12630 12630 port_map->map_did.port_id = d_id;
12631 12631 port_map->map_did.priv_lilp_posit = 0;
12632 12632 port_map->map_hard_addr.hard_addr = 0;
12633 12633 port_map->map_hard_addr.rsvd = 0;
12634 12634 port_map->map_state = PORT_DEVICE_INVALID;
12635 12635 port_map->map_type = PORT_DEVICE_NEW;
12636 12636 port_map->map_flags = 0;
12637 12637 port_map->map_pd = NULL;
12638 12638
12639 12639 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12640 12640
12641 12641 ASSERT(port != NULL);
12642 12642 }
12643 12643
12644 12644
12645 12645 /*
12646 12646 * Perform LINIT ELS
12647 12647 */
12648 12648 static int
12649 12649 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12650 12650 job_request_t *job)
12651 12651 {
12652 12652 int rval;
12653 12653 uint32_t d_id;
12654 12654 uint32_t s_id;
12655 12655 uint32_t lfa;
12656 12656 uchar_t class;
12657 12657 uint32_t ret;
12658 12658 fp_cmd_t *cmd;
12659 12659 fc_porttype_t ptype;
12660 12660 fc_packet_t *pkt;
12661 12661 fc_linit_req_t payload;
12662 12662 fc_remote_port_t *pd;
12663 12663
12664 12664 rval = 0;
12665 12665
12666 12666 ASSERT(job != NULL);
12667 12667 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12668 12668
12669 12669 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12670 12670 if (pd == NULL) {
12671 12671 fctl_ns_req_t *ns_cmd;
12672 12672
12673 12673 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12674 12674 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12675 12675 0, sleep);
12676 12676
12677 12677 if (ns_cmd == NULL) {
12678 12678 return (FC_NOMEM);
12679 12679 }
12680 12680 job->job_result = FC_SUCCESS;
12681 12681 ns_cmd->ns_cmd_code = NS_GID_PN;
12682 12682 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12683 12683
12684 12684 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12685 12685 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12686 12686 fctl_free_ns_cmd(ns_cmd);
12687 12687 return (FC_FAILURE);
12688 12688 }
12689 12689 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12690 12690 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12691 12691
12692 12692 fctl_free_ns_cmd(ns_cmd);
12693 12693 lfa = d_id & 0xFFFF00;
12694 12694
12695 12695 /*
12696 12696 * Given this D_ID, get the port type to see if
12697 12697 * we can do LINIT on the LFA
12698 12698 */
12699 12699 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12700 12700 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12701 12701 0, sleep);
12702 12702
12703 12703 if (ns_cmd == NULL) {
12704 12704 return (FC_NOMEM);
12705 12705 }
12706 12706
12707 12707 job->job_result = FC_SUCCESS;
12708 12708 ns_cmd->ns_cmd_code = NS_GPT_ID;
12709 12709
12710 12710 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12711 12711 ((ns_req_gpt_id_t *)
12712 12712 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12713 12713
12714 12714 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12715 12715 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12716 12716 fctl_free_ns_cmd(ns_cmd);
12717 12717 return (FC_FAILURE);
12718 12718 }
12719 12719 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12720 12720
12721 12721 fctl_free_ns_cmd(ns_cmd);
12722 12722
12723 12723 switch (ptype.port_type) {
12724 12724 case FC_NS_PORT_NL:
12725 12725 case FC_NS_PORT_F_NL:
12726 12726 case FC_NS_PORT_FL:
12727 12727 break;
12728 12728
12729 12729 default:
12730 12730 return (FC_FAILURE);
12731 12731 }
12732 12732 } else {
12733 12733 mutex_enter(&pd->pd_mutex);
12734 12734 ptype = pd->pd_porttype;
12735 12735
12736 12736 switch (pd->pd_porttype.port_type) {
12737 12737 case FC_NS_PORT_NL:
12738 12738 case FC_NS_PORT_F_NL:
12739 12739 case FC_NS_PORT_FL:
12740 12740 lfa = pd->pd_port_id.port_id & 0xFFFF00;
12741 12741 break;
12742 12742
12743 12743 default:
12744 12744 mutex_exit(&pd->pd_mutex);
12745 12745 return (FC_FAILURE);
12746 12746 }
12747 12747 mutex_exit(&pd->pd_mutex);
12748 12748 }
12749 12749
12750 12750 mutex_enter(&port->fp_mutex);
12751 12751 s_id = port->fp_port_id.port_id;
12752 12752 class = port->fp_ns_login_class;
12753 12753 mutex_exit(&port->fp_mutex);
12754 12754
12755 12755 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12756 12756 sizeof (fc_linit_resp_t), sleep, pd);
12757 12757 if (cmd == NULL) {
12758 12758 return (FC_NOMEM);
12759 12759 }
12760 12760
12761 12761 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12762 12762 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12763 12763 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12764 12764 cmd->cmd_retry_count = fp_retry_count;
12765 12765 cmd->cmd_ulp_pkt = NULL;
12766 12766
12767 12767 pkt = &cmd->cmd_pkt;
12768 12768 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12769 12769
12770 12770 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12771 12771
12772 12772 /*
12773 12773 * How does LIP work by the way ?
12774 12774 * If the L_Port receives three consecutive identical ordered
12775 12775 * sets whose first two characters (fully decoded) are equal to
12776 12776 * the values shown in Table 3 of FC-AL-2 then the L_Port shall
12777 12777 * recognize a Loop Initialization Primitive sequence. The
12778 12778 * character 3 determines the type of lip:
12779 12779 * LIP(F7) Normal LIP
12780 12780 * LIP(F8) Loop Failure LIP
12781 12781 *
12782 12782 * The possible combination for the 3rd and 4th bytes are:
12783 12783 * F7, F7 Normal Lip - No valid AL_PA
12784 12784 * F8, F8 Loop Failure - No valid AL_PA
12785 12785 * F7, AL_PS Normal Lip - Valid source AL_PA
12786 12786 * F8, AL_PS Loop Failure - Valid source AL_PA
12787 12787 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS
12788 12788 * And Normal Lip for all other loop members
12789 12789 * 0xFF AL_PS Vendor specific reset of all loop members
12790 12790 *
12791 12791 * Now, it may not always be that we, at the source, may have an
12792 12792 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12793 12793 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12794 12794 * payload we are going to set:
12795 12795 * lip_b3 = 0xF7; Normal LIP
12796 12796 * lip_b4 = 0xF7; No valid source AL_PA
12797 12797 */
12798 12798 payload.ls_code.ls_code = LA_ELS_LINIT;
12799 12799 payload.ls_code.mbz = 0;
12800 12800 payload.rsvd = 0;
12801 12801 payload.func = 0; /* Let Fabric determine the best way */
12802 12802 payload.lip_b3 = 0xF7; /* Normal LIP */
12803 12803 payload.lip_b4 = 0xF7; /* No valid source AL_PA */
12804 12804
12805 12805 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12806 12806 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12807 12807
12808 12808 job->job_counter = 1;
12809 12809
12810 12810 ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12811 12811 if (ret == FC_SUCCESS) {
12812 12812 fp_jobwait(job);
12813 12813 rval = job->job_result;
12814 12814 } else {
12815 12815 rval = FC_FAILURE;
12816 12816 fp_free_pkt(cmd);
12817 12817 }
12818 12818
12819 12819 return (rval);
12820 12820 }
12821 12821
12822 12822
12823 12823 /*
12824 12824 * Fill out the device handles with GAN response
12825 12825 */
12826 12826 static void
12827 12827 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12828 12828 ns_resp_gan_t *gan_resp)
12829 12829 {
12830 12830 fc_remote_node_t *node;
12831 12831 fc_porttype_t type;
12832 12832 fc_local_port_t *port;
12833 12833
12834 12834 ASSERT(pd != NULL);
12835 12835 ASSERT(handle != NULL);
12836 12836
12837 12837 port = pd->pd_port;
12838 12838
12839 12839 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12840 12840 " port_id=%x, sym_len=%d fc4-type=%x",
12841 12841 pd, gan_resp->gan_type_id.rsvd,
12842 12842 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12843 12843
12844 12844 mutex_enter(&pd->pd_mutex);
12845 12845
12846 12846 FC_GET_RSP(port, *handle, (uint8_t *)&type,
12847 12847 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12848 12848
12849 12849 pd->pd_porttype.port_type = type.port_type;
12850 12850 pd->pd_porttype.rsvd = 0;
12851 12851
12852 12852 pd->pd_spn_len = gan_resp->gan_spnlen;
12853 12853 if (pd->pd_spn_len) {
12854 12854 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12855 12855 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12856 12856 DDI_DEV_AUTOINCR);
12857 12857 }
12858 12858
12859 12859 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12860 12860 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12861 12861 DDI_DEV_AUTOINCR);
12862 12862 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12863 12863 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12864 12864 DDI_DEV_AUTOINCR);
12865 12865 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12866 12866 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12867 12867 DDI_DEV_AUTOINCR);
12868 12868
12869 12869 node = pd->pd_remote_nodep;
12870 12870 mutex_exit(&pd->pd_mutex);
12871 12871
12872 12872 mutex_enter(&node->fd_mutex);
12873 12873
12874 12874 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12875 12875 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12876 12876 DDI_DEV_AUTOINCR);
12877 12877
12878 12878 node->fd_snn_len = gan_resp->gan_snnlen;
12879 12879 if (node->fd_snn_len) {
12880 12880 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12881 12881 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12882 12882 DDI_DEV_AUTOINCR);
12883 12883 }
12884 12884
12885 12885 mutex_exit(&node->fd_mutex);
12886 12886 }
12887 12887
12888 12888
12889 12889 /*
12890 12890 * Handles all NS Queries (also means that this function
12891 12891 * doesn't handle NS object registration)
12892 12892 */
12893 12893 static int
12894 12894 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12895 12895 int polled, int sleep)
12896 12896 {
12897 12897 int rval;
12898 12898 fp_cmd_t *cmd;
12899 12899
12900 12900 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12901 12901
12902 12902 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12903 12903 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12904 12904 port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12905 12905 }
12906 12906
12907 12907 if (ns_cmd->ns_cmd_size == 0) {
12908 12908 return (FC_FAILURE);
12909 12909 }
12910 12910
12911 12911 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12912 12912 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12913 12913 ns_cmd->ns_resp_size, sleep, NULL);
12914 12914 if (cmd == NULL) {
12915 12915 return (FC_NOMEM);
12916 12916 }
12917 12917
12918 12918 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12919 12919 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12920 12920
12921 12921 if (polled) {
12922 12922 job->job_counter = 1;
12923 12923 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12924 12924 }
12925 12925 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12926 12926 if (rval != FC_SUCCESS) {
12927 12927 job->job_result = rval;
12928 12928 fp_iodone(cmd);
12929 12929 if (polled == 0) {
12930 12930 /*
12931 12931 * Return FC_SUCCESS to indicate that
12932 12932 * fp_iodone is performed already.
12933 12933 */
12934 12934 rval = FC_SUCCESS;
12935 12935 }
12936 12936 }
12937 12937
12938 12938 if (polled) {
12939 12939 fp_jobwait(job);
12940 12940 rval = job->job_result;
12941 12941 }
12942 12942
12943 12943 return (rval);
12944 12944 }
12945 12945
12946 12946
12947 12947 /*
12948 12948 * Initialize Common Transport request
12949 12949 */
12950 12950 static void
12951 12951 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12952 12952 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12953 12953 uint16_t resp_len, job_request_t *job)
12954 12954 {
12955 12955 uint32_t s_id;
12956 12956 uchar_t class;
12957 12957 fc_packet_t *pkt;
12958 12958 fc_ct_header_t ct;
12959 12959
12960 12960 ASSERT(!MUTEX_HELD(&port->fp_mutex));
12961 12961
12962 12962 mutex_enter(&port->fp_mutex);
12963 12963 s_id = port->fp_port_id.port_id;
12964 12964 class = port->fp_ns_login_class;
12965 12965 mutex_exit(&port->fp_mutex);
12966 12966
12967 12967 cmd->cmd_job = job;
12968 12968 cmd->cmd_private = ns_cmd;
12969 12969 pkt = &cmd->cmd_pkt;
12970 12970
12971 12971 ct.ct_rev = CT_REV;
12972 12972 ct.ct_inid = 0;
12973 12973 ct.ct_fcstype = FCSTYPE_DIRECTORY;
12974 12974 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12975 12975 ct.ct_options = 0;
12976 12976 ct.ct_reserved1 = 0;
12977 12977 ct.ct_cmdrsp = cmd_code;
12978 12978 ct.ct_aiusize = resp_len >> 2;
12979 12979 ct.ct_reserved2 = 0;
12980 12980 ct.ct_reason = 0;
12981 12981 ct.ct_expln = 0;
12982 12982 ct.ct_vendor = 0;
12983 12983
12984 12984 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12985 12985 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12986 12986
12987 12987 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12988 12988 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12989 12989 pkt->pkt_cmd_fhdr.s_id = s_id;
12990 12990 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12991 12991 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12992 12992 F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12993 12993 pkt->pkt_cmd_fhdr.seq_id = 0;
12994 12994 pkt->pkt_cmd_fhdr.df_ctl = 0;
12995 12995 pkt->pkt_cmd_fhdr.seq_cnt = 0;
12996 12996 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12997 12997 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12998 12998 pkt->pkt_cmd_fhdr.ro = 0;
12999 12999 pkt->pkt_cmd_fhdr.rsvd = 0;
13000 13000
13001 13001 pkt->pkt_comp = fp_ns_intr;
13002 13002 pkt->pkt_ulp_private = (opaque_t)cmd;
13003 13003 pkt->pkt_timeout = FP_NS_TIMEOUT;
13004 13004
13005 13005 if (cmd_buf) {
13006 13006 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
13007 13007 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13008 13008 cmd_len, DDI_DEV_AUTOINCR);
13009 13009 }
13010 13010
13011 13011 cmd->cmd_transport = port->fp_fca_tran->fca_transport;
13012 13012
13013 13013 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
13014 13014 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13015 13015 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
13016 13016 cmd->cmd_retry_count = fp_retry_count;
13017 13017 cmd->cmd_ulp_pkt = NULL;
13018 13018 }
13019 13019
13020 13020
13021 13021 /*
13022 13022 * Name Server request interrupt routine
13023 13023 */
13024 13024 static void
13025 13025 fp_ns_intr(fc_packet_t *pkt)
13026 13026 {
13027 13027 fp_cmd_t *cmd;
13028 13028 fc_local_port_t *port;
13029 13029 fc_ct_header_t resp_hdr;
13030 13030 fc_ct_header_t cmd_hdr;
13031 13031 fctl_ns_req_t *ns_cmd;
13032 13032
13033 13033 cmd = pkt->pkt_ulp_private;
13034 13034 port = cmd->cmd_port;
13035 13035
13036 13036 mutex_enter(&port->fp_mutex);
13037 13037 port->fp_out_fpcmds--;
13038 13038 mutex_exit(&port->fp_mutex);
13039 13039
13040 13040 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
13041 13041 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
13042 13042 ns_cmd = (fctl_ns_req_t *)
13043 13043 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
13044 13044 if (!FP_IS_PKT_ERROR(pkt)) {
13045 13045 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
13046 13046 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
13047 13047 DDI_DEV_AUTOINCR);
13048 13048
13049 13049 /*
13050 13050 * On x86 architectures, make sure the resp_hdr is big endian.
13051 13051 * This macro is a NOP on sparc architectures mainly because
13052 13052 * we don't want to end up wasting time since the end result
13053 13053 * is going to be the same.
13054 13054 */
13055 13055 MAKE_BE_32(&resp_hdr);
13056 13056
13057 13057 if (ns_cmd) {
13058 13058 /*
13059 13059 * Always copy out the response CT_HDR
13060 13060 */
13061 13061 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
13062 13062 sizeof (resp_hdr));
13063 13063 }
13064 13064
13065 13065 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
13066 13066 pkt->pkt_state = FC_PKT_FS_RJT;
13067 13067 pkt->pkt_reason = resp_hdr.ct_reason;
13068 13068 pkt->pkt_expln = resp_hdr.ct_expln;
13069 13069 }
13070 13070 }
13071 13071
13072 13072 if (FP_IS_PKT_ERROR(pkt)) {
13073 13073 if (ns_cmd) {
13074 13074 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13075 13075 ASSERT(ns_cmd->ns_pd != NULL);
13076 13076
13077 13077 /* Mark it OLD if not already done */
13078 13078 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13079 13079 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13080 13080 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13081 13081 }
13082 13082
13083 13083 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13084 13084 fctl_free_ns_cmd(ns_cmd);
13085 13085 ((fp_cmd_t *)
13086 13086 (pkt->pkt_ulp_private))->cmd_private = NULL;
13087 13087 }
13088 13088
13089 13089 }
13090 13090
13091 13091 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x "
13092 13092 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13093 13093 port->fp_port_id.port_id, pkt->pkt_state,
13094 13094 pkt->pkt_reason, pkt->pkt_expln,
13095 13095 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp);
13096 13096
13097 13097 (void) fp_common_intr(pkt, 1);
13098 13098
13099 13099 return;
13100 13100 }
13101 13101
13102 13102 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13103 13103 uint32_t d_id;
13104 13104 fc_local_port_t *port;
13105 13105 fp_cmd_t *cmd;
13106 13106
13107 13107 d_id = pkt->pkt_cmd_fhdr.d_id;
13108 13108 cmd = pkt->pkt_ulp_private;
13109 13109 port = cmd->cmd_port;
13110 13110 FP_TRACE(FP_NHEAD2(9, 0),
13111 13111 "Bogus NS response received for D_ID=%x", d_id);
13112 13112 }
13113 13113
13114 13114 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13115 13115 fp_gan_handler(pkt, ns_cmd);
13116 13116 return;
13117 13117 }
13118 13118
13119 13119 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13120 13120 cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13121 13121 if (ns_cmd) {
13122 13122 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13123 13123 fp_ns_query_handler(pkt, ns_cmd);
13124 13124 return;
13125 13125 }
13126 13126 }
13127 13127 }
13128 13128
13129 13129 fp_iodone(pkt->pkt_ulp_private);
13130 13130 }
13131 13131
13132 13132
13133 13133 /*
13134 13134 * Process NS_GAN response
13135 13135 */
13136 13136 static void
13137 13137 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13138 13138 {
13139 13139 int my_did;
13140 13140 fc_portid_t d_id;
13141 13141 fp_cmd_t *cmd;
13142 13142 fc_local_port_t *port;
13143 13143 fc_remote_port_t *pd;
13144 13144 ns_req_gan_t gan_req;
13145 13145 ns_resp_gan_t *gan_resp;
13146 13146
13147 13147 ASSERT(ns_cmd != NULL);
13148 13148
13149 13149 cmd = pkt->pkt_ulp_private;
13150 13150 port = cmd->cmd_port;
13151 13151
13152 13152 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13153 13153
13154 13154 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13155 13155 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13156 13156
13157 13157 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13158 13158
13159 13159 /*
13160 13160 * In this case the priv_lilp_posit field in reality
13161 13161 * is actually represents the relative position on a private loop.
13162 13162 * So zero it while dealing with Port Identifiers.
13163 13163 */
13164 13164 d_id.priv_lilp_posit = 0;
13165 13165 pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13166 13166 if (ns_cmd->ns_gan_sid == d_id.port_id) {
13167 13167 /*
13168 13168 * We've come a full circle; time to get out.
13169 13169 */
13170 13170 fp_iodone(cmd);
13171 13171 return;
13172 13172 }
13173 13173
13174 13174 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13175 13175 ns_cmd->ns_gan_sid = d_id.port_id;
13176 13176 }
13177 13177
13178 13178 mutex_enter(&port->fp_mutex);
13179 13179 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13180 13180 mutex_exit(&port->fp_mutex);
13181 13181
13182 13182 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13183 13183 port->fp_port_id.port_id, d_id.port_id);
13184 13184 if (my_did == 0) {
13185 13185 la_wwn_t pwwn;
13186 13186 la_wwn_t nwwn;
13187 13187
13188 13188 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13189 13189 "port=%p, d_id=%x, type_id=%x, "
13190 13190 "pwwn=%x %x %x %x %x %x %x %x, "
13191 13191 "nwwn=%x %x %x %x %x %x %x %x",
13192 13192 port, d_id.port_id, gan_resp->gan_type_id,
13193 13193
13194 13194 gan_resp->gan_pwwn.raw_wwn[0],
13195 13195 gan_resp->gan_pwwn.raw_wwn[1],
13196 13196 gan_resp->gan_pwwn.raw_wwn[2],
13197 13197 gan_resp->gan_pwwn.raw_wwn[3],
13198 13198 gan_resp->gan_pwwn.raw_wwn[4],
13199 13199 gan_resp->gan_pwwn.raw_wwn[5],
13200 13200 gan_resp->gan_pwwn.raw_wwn[6],
13201 13201 gan_resp->gan_pwwn.raw_wwn[7],
13202 13202
13203 13203 gan_resp->gan_nwwn.raw_wwn[0],
13204 13204 gan_resp->gan_nwwn.raw_wwn[1],
13205 13205 gan_resp->gan_nwwn.raw_wwn[2],
13206 13206 gan_resp->gan_nwwn.raw_wwn[3],
13207 13207 gan_resp->gan_nwwn.raw_wwn[4],
13208 13208 gan_resp->gan_nwwn.raw_wwn[5],
13209 13209 gan_resp->gan_nwwn.raw_wwn[6],
13210 13210 gan_resp->gan_nwwn.raw_wwn[7]);
13211 13211
13212 13212 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13213 13213 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13214 13214 DDI_DEV_AUTOINCR);
13215 13215
13216 13216 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13217 13217 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13218 13218 DDI_DEV_AUTOINCR);
13219 13219
13220 13220 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13221 13221 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13222 13222 "pd %x", port->fp_port_id.port_id, d_id.port_id);
13223 13223 pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13224 13224 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13225 13225 }
13226 13226 if (pd != NULL) {
13227 13227 fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13228 13228 pd, gan_resp);
13229 13229 }
13230 13230
13231 13231 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13232 13232 *((int *)ns_cmd->ns_data_buf) += 1;
13233 13233 }
13234 13234
13235 13235 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13236 13236 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13237 13237
13238 13238 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13239 13239 fc_port_dev_t *userbuf;
13240 13240
13241 13241 userbuf = ((fc_port_dev_t *)
13242 13242 ns_cmd->ns_data_buf) +
13243 13243 ns_cmd->ns_gan_index++;
13244 13244
13245 13245 userbuf->dev_did = d_id;
13246 13246
13247 13247 FC_GET_RSP(port, pkt->pkt_resp_acc,
13248 13248 (uint8_t *)userbuf->dev_type,
13249 13249 (uint8_t *)gan_resp->gan_fc4types,
13250 13250 sizeof (userbuf->dev_type),
13251 13251 DDI_DEV_AUTOINCR);
13252 13252
13253 13253 userbuf->dev_nwwn = nwwn;
13254 13254 userbuf->dev_pwwn = pwwn;
13255 13255
13256 13256 if (pd != NULL) {
13257 13257 mutex_enter(&pd->pd_mutex);
13258 13258 userbuf->dev_state = pd->pd_state;
13259 13259 userbuf->dev_hard_addr =
13260 13260 pd->pd_hard_addr;
13261 13261 mutex_exit(&pd->pd_mutex);
13262 13262 } else {
13263 13263 userbuf->dev_state =
13264 13264 PORT_DEVICE_INVALID;
13265 13265 }
13266 13266 } else if (ns_cmd->ns_flags &
13267 13267 FCTL_NS_BUF_IS_FC_PORTMAP) {
13268 13268 fc_portmap_t *map;
13269 13269
13270 13270 map = ((fc_portmap_t *)
13271 13271 ns_cmd->ns_data_buf) +
13272 13272 ns_cmd->ns_gan_index++;
13273 13273
13274 13274 /*
13275 13275 * First fill it like any new map
13276 13276 * and update the port device info
13277 13277 * below.
13278 13278 */
13279 13279 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13280 13280 map, gan_resp, d_id.port_id);
13281 13281 if (pd != NULL) {
13282 13282 fctl_copy_portmap(map, pd);
13283 13283 } else {
13284 13284 map->map_state = PORT_DEVICE_INVALID;
13285 13285 map->map_type = PORT_DEVICE_NOCHANGE;
13286 13286 }
13287 13287 } else {
13288 13288 caddr_t dst_ptr;
13289 13289
13290 13290 dst_ptr = ns_cmd->ns_data_buf +
13291 13291 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13292 13292
13293 13293 FC_GET_RSP(port, pkt->pkt_resp_acc,
13294 13294 (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13295 13295 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13296 13296 }
13297 13297 } else {
13298 13298 ns_cmd->ns_gan_index++;
13299 13299 }
13300 13300 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13301 13301 fp_iodone(cmd);
13302 13302 return;
13303 13303 }
13304 13304 }
13305 13305
13306 13306 gan_req.pid = d_id;
13307 13307
13308 13308 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13309 13309 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13310 13310 sizeof (gan_req), DDI_DEV_AUTOINCR);
13311 13311
13312 13312 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13313 13313 pkt->pkt_state = FC_PKT_TRAN_ERROR;
13314 13314 fp_iodone(cmd);
13315 13315 } else {
13316 13316 mutex_enter(&port->fp_mutex);
13317 13317 port->fp_out_fpcmds++;
13318 13318 mutex_exit(&port->fp_mutex);
13319 13319 }
13320 13320 }
13321 13321
13322 13322
13323 13323 /*
13324 13324 * Handle NS Query interrupt
13325 13325 */
13326 13326 static void
13327 13327 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13328 13328 {
13329 13329 fp_cmd_t *cmd;
13330 13330 fc_local_port_t *port;
13331 13331 caddr_t src_ptr;
13332 13332 uint32_t xfer_len;
13333 13333
13334 13334 cmd = pkt->pkt_ulp_private;
13335 13335 port = cmd->cmd_port;
13336 13336
13337 13337 xfer_len = ns_cmd->ns_resp_size;
13338 13338
13339 13339 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13340 13340 ns_cmd->ns_cmd_code, xfer_len);
13341 13341
13342 13342 if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13343 13343 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13344 13344
13345 13345 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13346 13346 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13347 13347 }
13348 13348
13349 13349 if (xfer_len <= ns_cmd->ns_data_len) {
13350 13350 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13351 13351 FC_GET_RSP(port, pkt->pkt_resp_acc,
13352 13352 (uint8_t *)ns_cmd->ns_data_buf,
13353 13353 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13354 13354 }
13355 13355
13356 13356 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13357 13357 ASSERT(ns_cmd->ns_pd != NULL);
13358 13358
13359 13359 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13360 13360 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13361 13361 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13362 13362 }
13363 13363 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13364 13364 }
13365 13365
13366 13366 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13367 13367 fctl_free_ns_cmd(ns_cmd);
13368 13368 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13369 13369 }
13370 13370 fp_iodone(cmd);
13371 13371 }
13372 13372
13373 13373
13374 13374 /*
13375 13375 * Handle unsolicited ADISC ELS request
13376 13376 */
13377 13377 static void
13378 13378 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13379 13379 fc_remote_port_t *pd, job_request_t *job)
13380 13380 {
13381 13381 int rval;
13382 13382 fp_cmd_t *cmd;
13383 13383
13384 13384 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13385 13385 port, pd->pd_port_id.port_id, pd->pd_state, pd);
13386 13386 mutex_enter(&pd->pd_mutex);
13387 13387 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13388 13388 mutex_exit(&pd->pd_mutex);
13389 13389 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13390 13390 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13391 13391 0, KM_SLEEP, pd);
13392 13392 if (cmd != NULL) {
13393 13393 fp_els_rjt_init(port, cmd, buf,
13394 13394 FC_ACTION_NON_RETRYABLE,
13395 13395 FC_REASON_INVALID_LINK_CTRL, job);
13396 13396
13397 13397 if (fp_sendcmd(port, cmd,
13398 13398 port->fp_fca_handle) != FC_SUCCESS) {
13399 13399 fp_free_pkt(cmd);
13400 13400 }
13401 13401 }
13402 13402 }
13403 13403 } else {
13404 13404 mutex_exit(&pd->pd_mutex);
13405 13405 /*
13406 13406 * Yes, yes, we don't have a hard address. But we
13407 13407 * we should still respond. Huh ? Visit 21.19.2
13408 13408 * of FC-PH-2 which essentially says that if an
13409 13409 * NL_Port doesn't have a hard address, or if a port
13410 13410 * does not have FC-AL capability, it shall report
13411 13411 * zeroes in this field.
13412 13412 */
13413 13413 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13414 13414 0, KM_SLEEP, pd);
13415 13415 if (cmd == NULL) {
13416 13416 return;
13417 13417 }
13418 13418 fp_adisc_acc_init(port, cmd, buf, job);
13419 13419 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13420 13420 if (rval != FC_SUCCESS) {
13421 13421 fp_free_pkt(cmd);
13422 13422 }
13423 13423 }
13424 13424 }
13425 13425
13426 13426
13427 13427 /*
13428 13428 * Initialize ADISC response.
13429 13429 */
13430 13430 static void
13431 13431 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13432 13432 job_request_t *job)
13433 13433 {
13434 13434 fc_packet_t *pkt;
13435 13435 la_els_adisc_t payload;
13436 13436
13437 13437 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13438 13438 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13439 13439 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13440 13440 cmd->cmd_retry_count = 1;
13441 13441 cmd->cmd_ulp_pkt = NULL;
13442 13442
13443 13443 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13444 13444 cmd->cmd_job = job;
13445 13445
13446 13446 pkt = &cmd->cmd_pkt;
13447 13447
13448 13448 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13449 13449
13450 13450 payload.ls_code.ls_code = LA_ELS_ACC;
13451 13451 payload.ls_code.mbz = 0;
13452 13452
13453 13453 mutex_enter(&port->fp_mutex);
13454 13454 payload.nport_id = port->fp_port_id;
13455 13455 payload.hard_addr = port->fp_hard_addr;
13456 13456 mutex_exit(&port->fp_mutex);
13457 13457
13458 13458 payload.port_wwn = port->fp_service_params.nport_ww_name;
13459 13459 payload.node_wwn = port->fp_service_params.node_ww_name;
13460 13460
13461 13461 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13462 13462 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13463 13463 }
13464 13464
13465 13465
13466 13466 /*
13467 13467 * Hold and Install the requested ULP drivers
13468 13468 */
13469 13469 static void
13470 13470 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13471 13471 {
13472 13472 int len;
13473 13473 int count;
13474 13474 int data_len;
13475 13475 major_t ulp_major;
13476 13476 caddr_t ulp_name;
13477 13477 caddr_t data_ptr;
13478 13478 caddr_t data_buf;
13479 13479
13480 13480 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13481 13481
13482 13482 data_buf = NULL;
13483 13483 if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13484 13484 DDI_PROP_DONTPASS, "load-ulp-list",
13485 13485 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13486 13486 return;
13487 13487 }
13488 13488
13489 13489 len = strlen(data_buf);
13490 13490 port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13491 13491
13492 13492 data_ptr = data_buf + len + 1;
13493 13493 for (count = 0; count < port->fp_ulp_nload; count++) {
13494 13494 len = strlen(data_ptr) + 1;
13495 13495 ulp_name = kmem_zalloc(len, KM_SLEEP);
13496 13496 bcopy(data_ptr, ulp_name, len);
13497 13497
13498 13498 ulp_major = ddi_name_to_major(ulp_name);
13499 13499
13500 13500 if (ulp_major != (major_t)-1) {
13501 13501 if (modload("drv", ulp_name) < 0) {
13502 13502 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13503 13503 0, NULL, "failed to load %s",
13504 13504 ulp_name);
13505 13505 }
13506 13506 } else {
13507 13507 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13508 13508 "%s isn't a valid driver", ulp_name);
13509 13509 }
13510 13510
13511 13511 kmem_free(ulp_name, len);
13512 13512 data_ptr += len; /* Skip to next field */
13513 13513 }
13514 13514
13515 13515 /*
13516 13516 * Free the memory allocated by DDI
13517 13517 */
13518 13518 if (data_buf != NULL) {
13519 13519 kmem_free(data_buf, data_len);
13520 13520 }
13521 13521 }
13522 13522
13523 13523
13524 13524 /*
13525 13525 * Perform LOGO operation
13526 13526 */
13527 13527 static int
13528 13528 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13529 13529 {
13530 13530 int rval;
13531 13531 fp_cmd_t *cmd;
13532 13532
13533 13533 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13534 13534 ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13535 13535
13536 13536 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13537 13537 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13538 13538
13539 13539 mutex_enter(&port->fp_mutex);
13540 13540 mutex_enter(&pd->pd_mutex);
13541 13541
13542 13542 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13543 13543 ASSERT(pd->pd_login_count == 1);
13544 13544
13545 13545 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13546 13546 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13547 13547 cmd->cmd_flags = 0;
13548 13548 cmd->cmd_retry_count = 1;
13549 13549 cmd->cmd_ulp_pkt = NULL;
13550 13550
13551 13551 fp_logo_init(pd, cmd, job);
13552 13552
13553 13553 mutex_exit(&pd->pd_mutex);
13554 13554 mutex_exit(&port->fp_mutex);
13555 13555
13556 13556 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13557 13557 if (rval != FC_SUCCESS) {
13558 13558 fp_iodone(cmd);
13559 13559 }
13560 13560
13561 13561 return (rval);
13562 13562 }
13563 13563
13564 13564
13565 13565 /*
13566 13566 * Perform Port attach callbacks to registered ULPs
13567 13567 */
13568 13568 static void
13569 13569 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13570 13570 {
13571 13571 fp_soft_attach_t *att;
13572 13572
13573 13573 att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13574 13574 att->att_cmd = cmd;
13575 13575 att->att_port = port;
13576 13576
13577 13577 /*
13578 13578 * We need to remember whether or not fctl_busy_port
13579 13579 * succeeded so we know whether or not to call
13580 13580 * fctl_idle_port when the task is complete.
13581 13581 */
13582 13582
13583 13583 if (fctl_busy_port(port) == 0) {
13584 13584 att->att_need_pm_idle = B_TRUE;
13585 13585 } else {
13586 13586 att->att_need_pm_idle = B_FALSE;
13587 13587 }
13588 13588
13589 13589 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13590 13590 att, KM_SLEEP);
13591 13591 }
13592 13592
13593 13593
13594 13594 /*
13595 13595 * Forward state change notifications on to interested ULPs.
13596 13596 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13597 13597 * real work.
13598 13598 */
13599 13599 static int
13600 13600 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13601 13601 {
13602 13602 fc_port_clist_t *clist;
13603 13603
13604 13604 clist = kmem_zalloc(sizeof (*clist), sleep);
13605 13605 if (clist == NULL) {
13606 13606 return (FC_NOMEM);
13607 13607 }
13608 13608
13609 13609 clist->clist_state = statec;
13610 13610
13611 13611 mutex_enter(&port->fp_mutex);
13612 13612 clist->clist_flags = port->fp_topology;
13613 13613 mutex_exit(&port->fp_mutex);
13614 13614
13615 13615 clist->clist_port = (opaque_t)port;
13616 13616 clist->clist_len = 0;
13617 13617 clist->clist_size = 0;
13618 13618 clist->clist_map = NULL;
13619 13619
13620 13620 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13621 13621 clist, KM_SLEEP);
13622 13622
13623 13623 return (FC_SUCCESS);
13624 13624 }
13625 13625
13626 13626
13627 13627 /*
13628 13628 * Get name server map
13629 13629 */
13630 13630 static int
13631 13631 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13632 13632 uint32_t *len, uint32_t sid)
13633 13633 {
13634 13634 int ret;
13635 13635 fctl_ns_req_t *ns_cmd;
13636 13636
13637 13637 /*
13638 13638 * Don't let the allocator do anything for response;
13639 13639 * we have have buffer ready to fillout.
13640 13640 */
13641 13641 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13642 13642 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13643 13643 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13644 13644
13645 13645 ns_cmd->ns_data_len = sizeof (**map) * (*len);
13646 13646 ns_cmd->ns_data_buf = (caddr_t)*map;
13647 13647
13648 13648 ASSERT(ns_cmd != NULL);
13649 13649
13650 13650 ns_cmd->ns_gan_index = 0;
13651 13651 ns_cmd->ns_gan_sid = sid;
13652 13652 ns_cmd->ns_cmd_code = NS_GA_NXT;
13653 13653 ns_cmd->ns_gan_max = *len;
13654 13654
13655 13655 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13656 13656
13657 13657 if (ns_cmd->ns_gan_index != *len) {
13658 13658 *len = ns_cmd->ns_gan_index;
13659 13659 }
13660 13660 ns_cmd->ns_data_len = 0;
13661 13661 ns_cmd->ns_data_buf = NULL;
13662 13662 fctl_free_ns_cmd(ns_cmd);
13663 13663
13664 13664 return (ret);
13665 13665 }
13666 13666
13667 13667
13668 13668 /*
13669 13669 * Create a remote port in Fabric topology by using NS services
13670 13670 */
13671 13671 static fc_remote_port_t *
13672 13672 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13673 13673 {
13674 13674 int rval;
13675 13675 job_request_t *job;
13676 13676 fctl_ns_req_t *ns_cmd;
13677 13677 fc_remote_port_t *pd;
13678 13678
13679 13679 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13680 13680
13681 13681 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13682 13682 port, d_id);
13683 13683
13684 13684 #ifdef DEBUG
13685 13685 mutex_enter(&port->fp_mutex);
13686 13686 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13687 13687 mutex_exit(&port->fp_mutex);
13688 13688 #endif
13689 13689
13690 13690 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13691 13691 if (job == NULL) {
13692 13692 return (NULL);
13693 13693 }
13694 13694
13695 13695 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13696 13696 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13697 13697 FCTL_NS_NO_DATA_BUF), sleep);
13698 13698 if (ns_cmd == NULL) {
13699 13699 return (NULL);
13700 13700 }
13701 13701
13702 13702 job->job_result = FC_SUCCESS;
13703 13703 ns_cmd->ns_gan_max = 1;
13704 13704 ns_cmd->ns_cmd_code = NS_GA_NXT;
13705 13705 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13706 13706 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13707 13707 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13708 13708
13709 13709 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13710 13710 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13711 13711 fctl_free_ns_cmd(ns_cmd);
13712 13712
13713 13713 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13714 13714 fctl_dealloc_job(job);
13715 13715 return (NULL);
13716 13716 }
13717 13717 fctl_dealloc_job(job);
13718 13718
13719 13719 pd = fctl_get_remote_port_by_did(port, d_id);
13720 13720
13721 13721 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13722 13722 port, d_id, pd);
13723 13723
13724 13724 return (pd);
13725 13725 }
13726 13726
13727 13727
13728 13728 /*
13729 13729 * Check for the permissions on an ioctl command. If it is required to have an
13730 13730 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13731 13731 * the ioctl command isn't in one of the list built, shut the door on that too.
13732 13732 *
13733 13733 * Certain ioctls perform hardware accesses in FCA drivers, and it needs
13734 13734 * to be made sure that users open the port for an exclusive access while
13735 13735 * performing those operations.
13736 13736 *
13737 13737 * This can prevent a casual user from inflicting damage on the port by
13738 13738 * sending these ioctls from multiple processes/threads (there is no good
13739 13739 * reason why one would need to do that) without actually realizing how
13740 13740 * expensive such commands could turn out to be.
13741 13741 *
13742 13742 * It is also important to note that, even with an exclusive access,
13743 13743 * multiple threads can share the same file descriptor and fire down
13744 13744 * commands in parallel. To prevent that the driver needs to make sure
13745 13745 * that such commands aren't in progress already. This is taken care of
13746 13746 * in the FP_EXCL_BUSY bit of fp_flag.
13747 13747 */
13748 13748 static int
13749 13749 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13750 13750 {
13751 13751 int ret = FC_FAILURE;
13752 13752 int count;
13753 13753
13754 13754 for (count = 0;
13755 13755 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13756 13756 count++) {
13757 13757 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13758 13758 if (fp_perm_list[count].fp_open_flag & open_flag) {
13759 13759 ret = FC_SUCCESS;
13760 13760 }
13761 13761 break;
13762 13762 }
13763 13763 }
13764 13764
13765 13765 return (ret);
13766 13766 }
13767 13767
13768 13768
13769 13769 /*
13770 13770 * Bind Port driver's unsolicited, state change callbacks
13771 13771 */
13772 13772 static int
13773 13773 fp_bind_callbacks(fc_local_port_t *port)
13774 13774 {
13775 13775 fc_fca_bind_info_t bind_info = {0};
13776 13776 fc_fca_port_info_t *port_info;
13777 13777 int rval = DDI_SUCCESS;
13778 13778 uint16_t class;
13779 13779 int node_namelen, port_namelen;
13780 13780 char *nname = NULL, *pname = NULL;
13781 13781
13782 13782 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13783 13783
13784 13784 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13785 13785 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13786 13786 "node-name", &nname) != DDI_PROP_SUCCESS) {
13787 13787 FP_TRACE(FP_NHEAD1(1, 0),
13788 13788 "fp_bind_callback fail to get node-name");
13789 13789 }
13790 13790 if (nname) {
13791 13791 fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13792 13792 }
13793 13793
13794 13794 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13795 13795 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13796 13796 "port-name", &pname) != DDI_PROP_SUCCESS) {
13797 13797 FP_TRACE(FP_NHEAD1(1, 0),
13798 13798 "fp_bind_callback fail to get port-name");
13799 13799 }
13800 13800 if (pname) {
13801 13801 fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13802 13802 }
13803 13803
13804 13804 if (port->fp_npiv_type == FC_NPIV_PORT) {
13805 13805 bind_info.port_npiv = 1;
13806 13806 }
13807 13807
13808 13808 /*
13809 13809 * fca_bind_port returns the FCA driver's handle for the local
13810 13810 * port instance. If the port number isn't supported it returns NULL.
13811 13811 * It also sets up callback in the FCA for various
13812 13812 * things like state change, ELS etc..
13813 13813 */
13814 13814 bind_info.port_statec_cb = fp_statec_cb;
13815 13815 bind_info.port_unsol_cb = fp_unsol_cb;
13816 13816 bind_info.port_num = port->fp_port_num;
13817 13817 bind_info.port_handle = (opaque_t)port;
13818 13818
13819 13819 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13820 13820
13821 13821 /*
13822 13822 * Hold the port driver mutex as the callbacks are bound until the
13823 13823 * service parameters are properly filled in (in order to be able to
13824 13824 * properly respond to unsolicited ELS requests)
13825 13825 */
13826 13826 mutex_enter(&port->fp_mutex);
13827 13827
13828 13828 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13829 13829 port->fp_fca_dip, port_info, &bind_info);
13830 13830
13831 13831 if (port->fp_fca_handle == NULL) {
13832 13832 rval = DDI_FAILURE;
13833 13833 goto exit;
13834 13834 }
13835 13835
13836 13836 /*
13837 13837 * Only fcoei will set this bit
13838 13838 */
13839 13839 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13840 13840 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13841 13841 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13842 13842 }
13843 13843
13844 13844 port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13845 13845 port->fp_service_params = port_info->pi_login_params;
13846 13846 port->fp_hard_addr = port_info->pi_hard_addr;
13847 13847
13848 13848 /* Copy from the FCA structure to the FP structure */
13849 13849 port->fp_hba_port_attrs = port_info->pi_attrs;
13850 13850
13851 13851 if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13852 13852 port->fp_rnid_init = 1;
13853 13853 bcopy(&port_info->pi_rnid_params.params,
13854 13854 &port->fp_rnid_params,
13855 13855 sizeof (port->fp_rnid_params));
13856 13856 } else {
13857 13857 port->fp_rnid_init = 0;
13858 13858 }
13859 13859
13860 13860 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13861 13861 if (node_namelen) {
13862 13862 bcopy(&port_info->pi_attrs.sym_node_name,
13863 13863 &port->fp_sym_node_name,
13864 13864 node_namelen);
13865 13865 port->fp_sym_node_namelen = node_namelen;
13866 13866 }
13867 13867 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13868 13868 if (port_namelen) {
13869 13869 bcopy(&port_info->pi_attrs.sym_port_name,
13870 13870 &port->fp_sym_port_name,
13871 13871 port_namelen);
13872 13872 port->fp_sym_port_namelen = port_namelen;
13873 13873 }
13874 13874
13875 13875 /* zero out the normally unused fields right away */
13876 13876 port->fp_service_params.ls_code.mbz = 0;
13877 13877 port->fp_service_params.ls_code.ls_code = 0;
13878 13878 bzero(&port->fp_service_params.reserved,
13879 13879 sizeof (port->fp_service_params.reserved));
13880 13880
13881 13881 class = port_info->pi_login_params.class_1.class_opt;
13882 13882 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13883 13883
13884 13884 class = port_info->pi_login_params.class_2.class_opt;
13885 13885 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13886 13886
13887 13887 class = port_info->pi_login_params.class_3.class_opt;
13888 13888 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13889 13889
13890 13890 exit:
13891 13891 if (nname) {
13892 13892 ddi_prop_free(nname);
13893 13893 }
13894 13894 if (pname) {
13895 13895 ddi_prop_free(pname);
13896 13896 }
13897 13897 mutex_exit(&port->fp_mutex);
13898 13898 kmem_free(port_info, sizeof (*port_info));
13899 13899
13900 13900 return (rval);
13901 13901 }
13902 13902
13903 13903
13904 13904 /*
13905 13905 * Retrieve FCA capabilities
13906 13906 */
13907 13907 static void
13908 13908 fp_retrieve_caps(fc_local_port_t *port)
13909 13909 {
13910 13910 int rval;
13911 13911 int ub_count;
13912 13912 fc_fcp_dma_t fcp_dma;
13913 13913 fc_reset_action_t action;
13914 13914 fc_dma_behavior_t dma_behavior;
13915 13915
13916 13916 ASSERT(!MUTEX_HELD(&port->fp_mutex));
13917 13917
13918 13918 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13919 13919 FC_CAP_UNSOL_BUF, &ub_count);
13920 13920
13921 13921 switch (rval) {
13922 13922 case FC_CAP_FOUND:
13923 13923 case FC_CAP_SETTABLE:
13924 13924 switch (ub_count) {
13925 13925 case 0:
13926 13926 break;
13927 13927
13928 13928 case -1:
13929 13929 ub_count = fp_unsol_buf_count;
13930 13930 break;
13931 13931
13932 13932 default:
13933 13933 /* 1/4th of total buffers is my share */
13934 13934 ub_count =
13935 13935 (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13936 13936 break;
13937 13937 }
13938 13938 break;
13939 13939
13940 13940 default:
13941 13941 ub_count = 0;
13942 13942 break;
13943 13943 }
13944 13944
13945 13945 mutex_enter(&port->fp_mutex);
13946 13946 port->fp_ub_count = ub_count;
13947 13947 mutex_exit(&port->fp_mutex);
13948 13948
13949 13949 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13950 13950 FC_CAP_POST_RESET_BEHAVIOR, &action);
13951 13951
13952 13952 switch (rval) {
13953 13953 case FC_CAP_FOUND:
13954 13954 case FC_CAP_SETTABLE:
13955 13955 switch (action) {
13956 13956 case FC_RESET_RETURN_NONE:
13957 13957 case FC_RESET_RETURN_ALL:
13958 13958 case FC_RESET_RETURN_OUTSTANDING:
13959 13959 break;
13960 13960
13961 13961 default:
13962 13962 action = FC_RESET_RETURN_NONE;
13963 13963 break;
13964 13964 }
13965 13965 break;
13966 13966
13967 13967 default:
13968 13968 action = FC_RESET_RETURN_NONE;
13969 13969 break;
13970 13970 }
13971 13971 mutex_enter(&port->fp_mutex);
13972 13972 port->fp_reset_action = action;
13973 13973 mutex_exit(&port->fp_mutex);
13974 13974
13975 13975 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13976 13976 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13977 13977
13978 13978 switch (rval) {
13979 13979 case FC_CAP_FOUND:
13980 13980 switch (dma_behavior) {
13981 13981 case FC_ALLOW_STREAMING:
13982 13982 /* FALLTHROUGH */
13983 13983 case FC_NO_STREAMING:
13984 13984 break;
13985 13985
13986 13986 default:
13987 13987 /*
13988 13988 * If capability was found and the value
13989 13989 * was incorrect assume the worst
13990 13990 */
13991 13991 dma_behavior = FC_NO_STREAMING;
13992 13992 break;
13993 13993 }
13994 13994 break;
13995 13995
13996 13996 default:
13997 13997 /*
13998 13998 * If capability was not defined - allow streaming; existing
13999 13999 * FCAs should not be affected.
14000 14000 */
14001 14001 dma_behavior = FC_ALLOW_STREAMING;
14002 14002 break;
14003 14003 }
14004 14004 mutex_enter(&port->fp_mutex);
14005 14005 port->fp_dma_behavior = dma_behavior;
14006 14006 mutex_exit(&port->fp_mutex);
14007 14007
14008 14008 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
14009 14009 FC_CAP_FCP_DMA, &fcp_dma);
14010 14010
14011 14011 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
14012 14012 fcp_dma != FC_DVMA_SPACE)) {
14013 14013 fcp_dma = FC_DVMA_SPACE;
14014 14014 }
14015 14015
14016 14016 mutex_enter(&port->fp_mutex);
14017 14017 port->fp_fcp_dma = fcp_dma;
14018 14018 mutex_exit(&port->fp_mutex);
14019 14019 }
14020 14020
14021 14021
14022 14022 /*
14023 14023 * Handle Domain, Area changes in the Fabric.
14024 14024 */
14025 14025 static void
14026 14026 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
14027 14027 job_request_t *job, int sleep)
14028 14028 {
14029 14029 #ifdef DEBUG
14030 14030 uint32_t dcnt;
14031 14031 #endif
14032 14032 int rval;
14033 14033 int send;
14034 14034 int index;
14035 14035 int listindex;
14036 14036 int login;
14037 14037 int job_flags;
14038 14038 char ww_name[17];
14039 14039 uint32_t d_id;
14040 14040 uint32_t count;
14041 14041 fctl_ns_req_t *ns_cmd;
14042 14042 fc_portmap_t *list;
14043 14043 fc_orphan_t *orp;
14044 14044 fc_orphan_t *norp;
14045 14045 fc_orphan_t *prev;
14046 14046 fc_remote_port_t *pd;
14047 14047 fc_remote_port_t *npd;
14048 14048 struct pwwn_hash *head;
14049 14049
14050 14050 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14051 14051 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14052 14052 0, sleep);
14053 14053 if (ns_cmd == NULL) {
14054 14054 mutex_enter(&port->fp_mutex);
14055 14055 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14056 14056 --port->fp_rscn_count;
14057 14057 }
14058 14058 mutex_exit(&port->fp_mutex);
14059 14059
14060 14060 return;
14061 14061 }
14062 14062 ns_cmd->ns_cmd_code = NS_GID_PN;
14063 14063
14064 14064 /*
14065 14065 * We need to get a new count of devices from the
14066 14066 * name server, which will also create any new devices
14067 14067 * as needed.
14068 14068 */
14069 14069
14070 14070 (void) fp_ns_get_devcount(port, job, 1, sleep);
14071 14071
14072 14072 FP_TRACE(FP_NHEAD1(3, 0),
14073 14073 "fp_validate_area_domain: get_devcount found %d devices",
14074 14074 port->fp_total_devices);
14075 14075
14076 14076 mutex_enter(&port->fp_mutex);
14077 14077
14078 14078 for (count = index = 0; index < pwwn_table_size; index++) {
14079 14079 head = &port->fp_pwwn_table[index];
14080 14080 pd = head->pwwn_head;
14081 14081 while (pd != NULL) {
14082 14082 mutex_enter(&pd->pd_mutex);
14083 14083 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14084 14084 if ((pd->pd_port_id.port_id & mask) == id &&
14085 14085 pd->pd_recepient == PD_PLOGI_INITIATOR) {
14086 14086 count++;
14087 14087 pd->pd_type = PORT_DEVICE_OLD;
14088 14088 pd->pd_flags = PD_ELS_MARK;
14089 14089 }
14090 14090 }
14091 14091 mutex_exit(&pd->pd_mutex);
14092 14092 pd = pd->pd_wwn_hnext;
14093 14093 }
14094 14094 }
14095 14095
14096 14096 #ifdef DEBUG
14097 14097 dcnt = count;
14098 14098 #endif /* DEBUG */
14099 14099
14100 14100 /*
14101 14101 * Since port->fp_orphan_count is declared an 'int' it is
14102 14102 * theoretically possible that the count could go negative.
14103 14103 *
14104 14104 * This would be bad and if that happens we really do want
14105 14105 * to know.
14106 14106 */
14107 14107
14108 14108 ASSERT(port->fp_orphan_count >= 0);
14109 14109
14110 14110 count += port->fp_orphan_count;
14111 14111
14112 14112 /*
14113 14113 * We add the port->fp_total_devices value to the count
14114 14114 * in the case where our port is newly attached. This is
14115 14115 * because we haven't done any discovery and we don't have
14116 14116 * any orphans in the port's orphan list. If we do not do
14117 14117 * this addition to count then we won't alloc enough kmem
14118 14118 * to do discovery with.
14119 14119 */
14120 14120
14121 14121 if (count == 0) {
14122 14122 count += port->fp_total_devices;
14123 14123 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14124 14124 "0x%x orphans found, using 0x%x",
14125 14125 port->fp_orphan_count, count);
14126 14126 }
14127 14127
14128 14128 mutex_exit(&port->fp_mutex);
14129 14129
14130 14130 /*
14131 14131 * Allocate the change list
14132 14132 */
14133 14133
14134 14134 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14135 14135 if (list == NULL) {
14136 14136 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14137 14137 " Not enough memory to service RSCNs"
14138 14138 " for %d ports, continuing...", count);
14139 14139
14140 14140 fctl_free_ns_cmd(ns_cmd);
14141 14141
14142 14142 mutex_enter(&port->fp_mutex);
14143 14143 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14144 14144 --port->fp_rscn_count;
14145 14145 }
14146 14146 mutex_exit(&port->fp_mutex);
14147 14147
14148 14148 return;
14149 14149 }
14150 14150
14151 14151 /*
14152 14152 * Attempt to validate or invalidate the devices that were
14153 14153 * already in the pwwn hash table.
14154 14154 */
14155 14155
14156 14156 mutex_enter(&port->fp_mutex);
14157 14157 for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14158 14158 head = &port->fp_pwwn_table[index];
14159 14159 npd = head->pwwn_head;
14160 14160
14161 14161 while ((pd = npd) != NULL) {
14162 14162 npd = pd->pd_wwn_hnext;
14163 14163
14164 14164 mutex_enter(&pd->pd_mutex);
14165 14165 if ((pd->pd_port_id.port_id & mask) == id &&
14166 14166 pd->pd_flags == PD_ELS_MARK) {
14167 14167 la_wwn_t *pwwn;
14168 14168
14169 14169 job->job_result = FC_SUCCESS;
14170 14170
14171 14171 ((ns_req_gid_pn_t *)
14172 14172 (ns_cmd->ns_cmd_buf))->pwwn =
14173 14173 pd->pd_port_name;
14174 14174
14175 14175 pwwn = &pd->pd_port_name;
14176 14176 d_id = pd->pd_port_id.port_id;
14177 14177
14178 14178 mutex_exit(&pd->pd_mutex);
14179 14179 mutex_exit(&port->fp_mutex);
14180 14180
14181 14181 rval = fp_ns_query(port, ns_cmd, job, 1,
14182 14182 sleep);
14183 14183 if (rval != FC_SUCCESS) {
14184 14184 fc_wwn_to_str(pwwn, ww_name);
14185 14185
14186 14186 FP_TRACE(FP_NHEAD1(3, 0),
14187 14187 "AREA RSCN: PD disappeared; "
14188 14188 "d_id=%x, PWWN=%s", d_id, ww_name);
14189 14189
14190 14190 FP_TRACE(FP_NHEAD2(9, 0),
14191 14191 "N_x Port with D_ID=%x,"
14192 14192 " PWWN=%s disappeared from fabric",
14193 14193 d_id, ww_name);
14194 14194
14195 14195 fp_fillout_old_map(list + listindex++,
14196 14196 pd, 1);
14197 14197 } else {
14198 14198 fctl_copy_portmap(list + listindex++,
14199 14199 pd);
14200 14200
14201 14201 mutex_enter(&pd->pd_mutex);
14202 14202 pd->pd_flags = PD_ELS_IN_PROGRESS;
14203 14203 mutex_exit(&pd->pd_mutex);
14204 14204 }
14205 14205
14206 14206 mutex_enter(&port->fp_mutex);
14207 14207 } else {
14208 14208 mutex_exit(&pd->pd_mutex);
14209 14209 }
14210 14210 }
14211 14211 }
14212 14212
14213 14213 mutex_exit(&port->fp_mutex);
14214 14214
14215 14215 ASSERT(listindex == dcnt);
14216 14216
14217 14217 job->job_counter = listindex;
14218 14218 job_flags = job->job_flags;
14219 14219 job->job_flags |= JOB_TYPE_FP_ASYNC;
14220 14220
14221 14221 /*
14222 14222 * Login (if we were the initiator) or validate devices in the
14223 14223 * port map.
14224 14224 */
14225 14225
14226 14226 for (index = 0; index < listindex; index++) {
14227 14227 pd = list[index].map_pd;
14228 14228
14229 14229 mutex_enter(&pd->pd_mutex);
14230 14230 ASSERT((pd->pd_port_id.port_id & mask) == id);
14231 14231
14232 14232 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14233 14233 ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14234 14234 mutex_exit(&pd->pd_mutex);
14235 14235 fp_jobdone(job);
14236 14236 continue;
14237 14237 }
14238 14238
14239 14239 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14240 14240 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14241 14241 d_id = pd->pd_port_id.port_id;
14242 14242 mutex_exit(&pd->pd_mutex);
14243 14243
14244 14244 if ((d_id & mask) == id && send) {
14245 14245 if (login) {
14246 14246 FP_TRACE(FP_NHEAD1(6, 0),
14247 14247 "RSCN and PLOGI request;"
14248 14248 " pd=%p, job=%p d_id=%x, index=%d", pd,
14249 14249 job, d_id, index);
14250 14250
14251 14251 rval = fp_port_login(port, d_id, job,
14252 14252 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14253 14253 if (rval != FC_SUCCESS) {
14254 14254 mutex_enter(&pd->pd_mutex);
14255 14255 pd->pd_flags = PD_IDLE;
14256 14256 mutex_exit(&pd->pd_mutex);
14257 14257
14258 14258 job->job_result = rval;
14259 14259 fp_jobdone(job);
14260 14260 }
14261 14261 FP_TRACE(FP_NHEAD1(1, 0),
14262 14262 "PLOGI succeeded:no skip(1) for "
14263 14263 "D_ID %x", d_id);
14264 14264 list[index].map_flags |=
14265 14265 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14266 14266 } else {
14267 14267 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14268 14268 " pd=%p, job=%p d_id=%x, index=%d", pd,
14269 14269 job, d_id, index);
14270 14270
14271 14271 rval = fp_ns_validate_device(port, pd, job,
14272 14272 0, sleep);
14273 14273 if (rval != FC_SUCCESS) {
14274 14274 fp_jobdone(job);
14275 14275 }
14276 14276 mutex_enter(&pd->pd_mutex);
14277 14277 pd->pd_flags = PD_IDLE;
14278 14278 mutex_exit(&pd->pd_mutex);
14279 14279 }
14280 14280 } else {
14281 14281 FP_TRACE(FP_NHEAD1(6, 0),
14282 14282 "RSCN and NO request sent; pd=%p,"
14283 14283 " d_id=%x, index=%d", pd, d_id, index);
14284 14284
14285 14285 mutex_enter(&pd->pd_mutex);
14286 14286 pd->pd_flags = PD_IDLE;
14287 14287 mutex_exit(&pd->pd_mutex);
14288 14288
14289 14289 fp_jobdone(job);
14290 14290 }
14291 14291 }
14292 14292
14293 14293 if (listindex) {
14294 14294 fctl_jobwait(job);
14295 14295 }
14296 14296 job->job_flags = job_flags;
14297 14297
14298 14298 /*
14299 14299 * Orphan list validation.
14300 14300 */
14301 14301 mutex_enter(&port->fp_mutex);
14302 14302 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14303 14303 orp != NULL; orp = norp) {
14304 14304 norp = orp->orp_next;
14305 14305 mutex_exit(&port->fp_mutex);
14306 14306
14307 14307 job->job_counter = 1;
14308 14308 job->job_result = FC_SUCCESS;
14309 14309 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14310 14310
14311 14311 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14312 14312
14313 14313 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14314 14314 ((ns_resp_gid_pn_t *)
14315 14315 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14316 14316
14317 14317 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14318 14318 if (rval == FC_SUCCESS) {
14319 14319 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14320 14320 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14321 14321 if (pd != NULL) {
14322 14322 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14323 14323
14324 14324 FP_TRACE(FP_NHEAD1(6, 0),
14325 14325 "RSCN and ORPHAN list "
14326 14326 "success; d_id=%x, PWWN=%s", d_id, ww_name);
14327 14327
14328 14328 FP_TRACE(FP_NHEAD2(6, 0),
14329 14329 "N_x Port with D_ID=%x, PWWN=%s reappeared"
14330 14330 " in fabric", d_id, ww_name);
14331 14331
14332 14332 mutex_enter(&port->fp_mutex);
14333 14333 if (prev) {
14334 14334 prev->orp_next = orp->orp_next;
14335 14335 } else {
14336 14336 ASSERT(orp == port->fp_orphan_list);
14337 14337 port->fp_orphan_list = orp->orp_next;
14338 14338 }
14339 14339 port->fp_orphan_count--;
14340 14340 mutex_exit(&port->fp_mutex);
14341 14341
14342 14342 kmem_free(orp, sizeof (*orp));
14343 14343 fctl_copy_portmap(list + listindex++, pd);
14344 14344 } else {
14345 14345 prev = orp;
14346 14346 }
14347 14347 } else {
14348 14348 prev = orp;
14349 14349 }
14350 14350 mutex_enter(&port->fp_mutex);
14351 14351 }
14352 14352 mutex_exit(&port->fp_mutex);
14353 14353
14354 14354 /*
14355 14355 * One more pass through the list to delist old devices from
14356 14356 * the d_id and pwwn tables and possibly add to the orphan list.
14357 14357 */
14358 14358
14359 14359 for (index = 0; index < listindex; index++) {
14360 14360 pd = list[index].map_pd;
14361 14361 ASSERT(pd != NULL);
14362 14362
14363 14363 /*
14364 14364 * Update PLOGI results; For NS validation
14365 14365 * of orphan list, it is redundant
14366 14366 *
14367 14367 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14368 14368 * appropriate as fctl_copy_portmap() will clear map_flags.
14369 14369 */
14370 14370 if (list[index].map_flags &
14371 14371 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14372 14372 fctl_copy_portmap(list + index, pd);
14373 14373 list[index].map_flags |=
14374 14374 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14375 14375 } else {
14376 14376 fctl_copy_portmap(list + index, pd);
14377 14377 }
14378 14378
14379 14379 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14380 14380 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14381 14381 pd, pd->pd_port_id.port_id,
14382 14382 pd->pd_port_name.raw_wwn[0],
14383 14383 pd->pd_port_name.raw_wwn[1],
14384 14384 pd->pd_port_name.raw_wwn[2],
14385 14385 pd->pd_port_name.raw_wwn[3],
14386 14386 pd->pd_port_name.raw_wwn[4],
14387 14387 pd->pd_port_name.raw_wwn[5],
14388 14388 pd->pd_port_name.raw_wwn[6],
14389 14389 pd->pd_port_name.raw_wwn[7]);
14390 14390
14391 14391 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14392 14392 "results continued, pd=%p type=%x, flags=%x, state=%x",
14393 14393 pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14394 14394
14395 14395 mutex_enter(&pd->pd_mutex);
14396 14396 if (pd->pd_type == PORT_DEVICE_OLD) {
14397 14397 int initiator;
14398 14398
14399 14399 pd->pd_flags = PD_IDLE;
14400 14400 initiator = (pd->pd_recepient ==
14401 14401 PD_PLOGI_INITIATOR) ? 1 : 0;
14402 14402
14403 14403 mutex_exit(&pd->pd_mutex);
14404 14404
14405 14405 mutex_enter(&port->fp_mutex);
14406 14406 mutex_enter(&pd->pd_mutex);
14407 14407
14408 14408 pd->pd_state = PORT_DEVICE_INVALID;
14409 14409 fctl_delist_did_table(port, pd);
14410 14410 fctl_delist_pwwn_table(port, pd);
14411 14411
14412 14412 mutex_exit(&pd->pd_mutex);
14413 14413 mutex_exit(&port->fp_mutex);
14414 14414
14415 14415 if (initiator) {
14416 14416 (void) fctl_add_orphan(port, pd, sleep);
14417 14417 }
14418 14418 list[index].map_pd = pd;
14419 14419 } else {
14420 14420 ASSERT(pd->pd_flags == PD_IDLE);
14421 14421 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14422 14422 /*
14423 14423 * Reset LOGO tolerance to zero
14424 14424 */
14425 14425 fctl_tc_reset(&pd->pd_logo_tc);
14426 14426 }
14427 14427 mutex_exit(&pd->pd_mutex);
14428 14428 }
14429 14429 }
14430 14430
14431 14431 if (ns_cmd) {
14432 14432 fctl_free_ns_cmd(ns_cmd);
14433 14433 }
14434 14434 if (listindex) {
14435 14435 (void) fp_ulp_devc_cb(port, list, listindex, count,
14436 14436 sleep, 0);
14437 14437 } else {
14438 14438 kmem_free(list, sizeof (*list) * count);
14439 14439
14440 14440 mutex_enter(&port->fp_mutex);
14441 14441 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14442 14442 --port->fp_rscn_count;
14443 14443 }
14444 14444 mutex_exit(&port->fp_mutex);
14445 14445 }
14446 14446 }
14447 14447
14448 14448
14449 14449 /*
14450 14450 * Work hard to make sense out of an RSCN page.
14451 14451 */
14452 14452 static void
14453 14453 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14454 14454 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14455 14455 int *listindex, int sleep)
14456 14456 {
14457 14457 int rval;
14458 14458 char ww_name[17];
14459 14459 la_wwn_t *pwwn;
14460 14460 fc_remote_port_t *pwwn_pd;
14461 14461 fc_remote_port_t *did_pd;
14462 14462
14463 14463 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14464 14464
14465 14465 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14466 14466 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14467 14467 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14468 14468
14469 14469 if (did_pd != NULL) {
14470 14470 mutex_enter(&did_pd->pd_mutex);
14471 14471 if (did_pd->pd_flags != PD_IDLE) {
14472 14472 mutex_exit(&did_pd->pd_mutex);
14473 14473 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14474 14474 "PD is BUSY; port=%p, d_id=%x, pd=%p",
14475 14475 port, page->aff_d_id, did_pd);
14476 14476 return;
14477 14477 }
14478 14478 did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14479 14479 mutex_exit(&did_pd->pd_mutex);
14480 14480 }
14481 14481
14482 14482 job->job_counter = 1;
14483 14483
14484 14484 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14485 14485
14486 14486 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14487 14487 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14488 14488
14489 14489 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14490 14490 rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14491 14491
14492 14492 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14493 14493 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14494 14494 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14495 14495 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14496 14496 ns_cmd->ns_resp_hdr.ct_expln);
14497 14497
14498 14498 job->job_counter = 1;
14499 14499
14500 14500 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14501 14501 /*
14502 14502 * What this means is that the D_ID
14503 14503 * disappeared from the Fabric.
14504 14504 */
14505 14505 if (did_pd == NULL) {
14506 14506 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14507 14507 " NULL PD disappeared, rval=%x", rval);
14508 14508 return;
14509 14509 }
14510 14510
14511 14511 fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14512 14512
14513 14513 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14514 14514 (uint32_t)(uintptr_t)job->job_cb_arg;
14515 14515
14516 14516 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14517 14517
14518 14518 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14519 14519 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14520 14520
14521 14521 FP_TRACE(FP_NHEAD2(9, 0),
14522 14522 "GPN_ID for D_ID=%x failed", page->aff_d_id);
14523 14523
14524 14524 FP_TRACE(FP_NHEAD2(9, 0),
14525 14525 "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14526 14526 " fabric", page->aff_d_id, ww_name);
14527 14527
14528 14528 mutex_enter(&did_pd->pd_mutex);
14529 14529 did_pd->pd_flags = PD_IDLE;
14530 14530 mutex_exit(&did_pd->pd_mutex);
14531 14531
14532 14532 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14533 14533 "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14534 14534
14535 14535 return;
14536 14536 }
14537 14537
14538 14538 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14539 14539
14540 14540 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14541 14541 /*
14542 14542 * There is no change. Do PLOGI again and add it to
14543 14543 * ULP portmap baggage and return. Note: When RSCNs
14544 14544 * arrive with per page states, the need for PLOGI
14545 14545 * can be determined correctly.
14546 14546 */
14547 14547 mutex_enter(&pwwn_pd->pd_mutex);
14548 14548 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14549 14549 mutex_exit(&pwwn_pd->pd_mutex);
14550 14550
14551 14551 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14552 14552 (uint32_t)(uintptr_t)job->job_cb_arg;
14553 14553
14554 14554 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14555 14555
14556 14556 mutex_enter(&pwwn_pd->pd_mutex);
14557 14557 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14558 14558 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14559 14559 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14560 14560 mutex_exit(&pwwn_pd->pd_mutex);
14561 14561
14562 14562 rval = fp_port_login(port, page->aff_d_id, job,
14563 14563 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14564 14564 if (rval == FC_SUCCESS) {
14565 14565 fp_jobwait(job);
14566 14566 rval = job->job_result;
14567 14567
14568 14568 /*
14569 14569 * Reset LOGO tolerance to zero
14570 14570 * Also we are the PLOGI initiator now.
14571 14571 */
14572 14572 mutex_enter(&pwwn_pd->pd_mutex);
14573 14573 fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14574 14574 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14575 14575 mutex_exit(&pwwn_pd->pd_mutex);
14576 14576 }
14577 14577
14578 14578 if (rval == FC_SUCCESS) {
14579 14579 struct fc_portmap *map =
14580 14580 listptr + *listindex - 1;
14581 14581
14582 14582 FP_TRACE(FP_NHEAD1(1, 0),
14583 14583 "PLOGI succeeded: no skip(2)"
14584 14584 " for D_ID %x", page->aff_d_id);
14585 14585 map->map_flags |=
14586 14586 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14587 14587 } else {
14588 14588 FP_TRACE(FP_NHEAD2(9, rval),
14589 14589 "PLOGI to D_ID=%x failed", page->aff_d_id);
14590 14590
14591 14591 FP_TRACE(FP_NHEAD2(9, 0),
14592 14592 "N_x Port with D_ID=%x, PWWN=%s"
14593 14593 " disappeared from fabric",
14594 14594 page->aff_d_id, ww_name);
14595 14595
14596 14596 fp_fillout_old_map(listptr +
14597 14597 *listindex - 1, pwwn_pd, 0);
14598 14598 }
14599 14599 } else {
14600 14600 mutex_exit(&pwwn_pd->pd_mutex);
14601 14601 }
14602 14602
14603 14603 mutex_enter(&did_pd->pd_mutex);
14604 14604 did_pd->pd_flags = PD_IDLE;
14605 14605 mutex_exit(&did_pd->pd_mutex);
14606 14606
14607 14607 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14608 14608 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14609 14609 job->job_result, pwwn_pd);
14610 14610
14611 14611 return;
14612 14612 }
14613 14613
14614 14614 if (did_pd == NULL && pwwn_pd == NULL) {
14615 14615
14616 14616 fc_orphan_t *orp = NULL;
14617 14617 fc_orphan_t *norp = NULL;
14618 14618 fc_orphan_t *prev = NULL;
14619 14619
14620 14620 /*
14621 14621 * Hunt down the orphan list before giving up.
14622 14622 */
14623 14623
14624 14624 mutex_enter(&port->fp_mutex);
14625 14625 if (port->fp_orphan_count) {
14626 14626
14627 14627 for (orp = port->fp_orphan_list; orp; orp = norp) {
14628 14628 norp = orp->orp_next;
14629 14629
14630 14630 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14631 14631 prev = orp;
14632 14632 continue;
14633 14633 }
14634 14634
14635 14635 if (prev) {
14636 14636 prev->orp_next = orp->orp_next;
14637 14637 } else {
14638 14638 ASSERT(orp ==
14639 14639 port->fp_orphan_list);
14640 14640 port->fp_orphan_list =
14641 14641 orp->orp_next;
14642 14642 }
14643 14643 port->fp_orphan_count--;
14644 14644 break;
14645 14645 }
14646 14646 }
14647 14647
14648 14648 mutex_exit(&port->fp_mutex);
14649 14649 pwwn_pd = fp_create_remote_port_by_ns(port,
14650 14650 page->aff_d_id, sleep);
14651 14651
14652 14652 if (pwwn_pd != NULL) {
14653 14653
14654 14654 if (orp) {
14655 14655 fc_wwn_to_str(&orp->orp_pwwn,
14656 14656 ww_name);
14657 14657
14658 14658 FP_TRACE(FP_NHEAD2(9, 0),
14659 14659 "N_x Port with D_ID=%x,"
14660 14660 " PWWN=%s reappeared in fabric",
14661 14661 page->aff_d_id, ww_name);
14662 14662
14663 14663 kmem_free(orp, sizeof (*orp));
14664 14664 }
14665 14665
14666 14666 (listptr + *listindex)->
14667 14667 map_rscn_info.ulp_rscn_count =
14668 14668 (uint32_t)(uintptr_t)job->job_cb_arg;
14669 14669
14670 14670 fctl_copy_portmap(listptr +
14671 14671 (*listindex)++, pwwn_pd);
14672 14672 }
14673 14673
14674 14674 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14675 14675 "Case TWO", page->aff_d_id);
14676 14676
14677 14677 return;
14678 14678 }
14679 14679
14680 14680 if (pwwn_pd != NULL && did_pd == NULL) {
14681 14681 uint32_t old_d_id;
14682 14682 uint32_t d_id = page->aff_d_id;
14683 14683
14684 14684 /*
14685 14685 * What this means is there is a new D_ID for this
14686 14686 * Port WWN. Take out the port device off D_ID
14687 14687 * list and put it back with a new D_ID. Perform
14688 14688 * PLOGI if already logged in.
14689 14689 */
14690 14690 mutex_enter(&port->fp_mutex);
14691 14691 mutex_enter(&pwwn_pd->pd_mutex);
14692 14692
14693 14693 old_d_id = pwwn_pd->pd_port_id.port_id;
14694 14694
14695 14695 fctl_delist_did_table(port, pwwn_pd);
14696 14696
14697 14697 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14698 14698 (uint32_t)(uintptr_t)job->job_cb_arg;
14699 14699
14700 14700 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14701 14701 &d_id, NULL);
14702 14702 fctl_enlist_did_table(port, pwwn_pd);
14703 14703
14704 14704 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14705 14705 " Case THREE, pd=%p,"
14706 14706 " state=%x", pwwn_pd, pwwn_pd->pd_state);
14707 14707
14708 14708 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14709 14709 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14710 14710 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14711 14711
14712 14712 mutex_exit(&pwwn_pd->pd_mutex);
14713 14713 mutex_exit(&port->fp_mutex);
14714 14714
14715 14715 FP_TRACE(FP_NHEAD2(9, 0),
14716 14716 "N_x Port with D_ID=%x, PWWN=%s has a new"
14717 14717 " D_ID=%x now", old_d_id, ww_name, d_id);
14718 14718
14719 14719 rval = fp_port_login(port, page->aff_d_id, job,
14720 14720 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14721 14721 if (rval == FC_SUCCESS) {
14722 14722 fp_jobwait(job);
14723 14723 rval = job->job_result;
14724 14724 }
14725 14725
14726 14726 if (rval != FC_SUCCESS) {
14727 14727 fp_fillout_old_map(listptr +
14728 14728 *listindex - 1, pwwn_pd, 0);
14729 14729 }
14730 14730 } else {
14731 14731 mutex_exit(&pwwn_pd->pd_mutex);
14732 14732 mutex_exit(&port->fp_mutex);
14733 14733 }
14734 14734
14735 14735 return;
14736 14736 }
14737 14737
14738 14738 if (pwwn_pd == NULL && did_pd != NULL) {
14739 14739 fc_portmap_t *ptr;
14740 14740 uint32_t len = 1;
14741 14741 char old_ww_name[17];
14742 14742
14743 14743 mutex_enter(&did_pd->pd_mutex);
14744 14744 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14745 14745 mutex_exit(&did_pd->pd_mutex);
14746 14746
14747 14747 fc_wwn_to_str(pwwn, ww_name);
14748 14748
14749 14749 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14750 14750 (uint32_t)(uintptr_t)job->job_cb_arg;
14751 14751
14752 14752 /*
14753 14753 * What this means is that there is a new Port WWN for
14754 14754 * this D_ID; Mark the Port device as old and provide
14755 14755 * the new PWWN and D_ID combination as new.
14756 14756 */
14757 14757 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14758 14758
14759 14759 FP_TRACE(FP_NHEAD2(9, 0),
14760 14760 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14761 14761 page->aff_d_id, old_ww_name, ww_name);
14762 14762
14763 14763 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14764 14764 (uint32_t)(uintptr_t)job->job_cb_arg;
14765 14765
14766 14766 ptr = listptr + (*listindex)++;
14767 14767
14768 14768 job->job_counter = 1;
14769 14769
14770 14770 if (fp_ns_getmap(port, job, &ptr, &len,
14771 14771 page->aff_d_id - 1) != FC_SUCCESS) {
14772 14772 (*listindex)--;
14773 14773 }
14774 14774
14775 14775 mutex_enter(&did_pd->pd_mutex);
14776 14776 did_pd->pd_flags = PD_IDLE;
14777 14777 mutex_exit(&did_pd->pd_mutex);
14778 14778
14779 14779 return;
14780 14780 }
14781 14781
14782 14782 /*
14783 14783 * A weird case of Port WWN and D_ID existence but not matching up
14784 14784 * between them. Trust your instincts - Take the port device handle
14785 14785 * off Port WWN list, fix it with new Port WWN and put it back, In
14786 14786 * the mean time mark the port device corresponding to the old port
14787 14787 * WWN as OLD.
14788 14788 */
14789 14789 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14790 14790 " did_pd=%p", pwwn_pd, did_pd);
14791 14791
14792 14792 mutex_enter(&port->fp_mutex);
14793 14793 mutex_enter(&pwwn_pd->pd_mutex);
14794 14794
14795 14795 pwwn_pd->pd_type = PORT_DEVICE_OLD;
14796 14796 pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14797 14797 fctl_delist_did_table(port, pwwn_pd);
14798 14798 fctl_delist_pwwn_table(port, pwwn_pd);
14799 14799
14800 14800 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14801 14801 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14802 14802 pwwn_pd->pd_port_id.port_id,
14803 14803
14804 14804 pwwn_pd->pd_port_name.raw_wwn[0],
14805 14805 pwwn_pd->pd_port_name.raw_wwn[1],
14806 14806 pwwn_pd->pd_port_name.raw_wwn[2],
14807 14807 pwwn_pd->pd_port_name.raw_wwn[3],
14808 14808 pwwn_pd->pd_port_name.raw_wwn[4],
14809 14809 pwwn_pd->pd_port_name.raw_wwn[5],
14810 14810 pwwn_pd->pd_port_name.raw_wwn[6],
14811 14811 pwwn_pd->pd_port_name.raw_wwn[7]);
14812 14812
14813 14813 mutex_exit(&pwwn_pd->pd_mutex);
14814 14814 mutex_exit(&port->fp_mutex);
14815 14815
14816 14816 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14817 14817 (uint32_t)(uintptr_t)job->job_cb_arg;
14818 14818
14819 14819 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14820 14820
14821 14821 mutex_enter(&port->fp_mutex);
14822 14822 mutex_enter(&did_pd->pd_mutex);
14823 14823
14824 14824 fctl_delist_pwwn_table(port, did_pd);
14825 14825
14826 14826 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14827 14827 (uint32_t)(uintptr_t)job->job_cb_arg;
14828 14828
14829 14829 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14830 14830 fctl_enlist_pwwn_table(port, did_pd);
14831 14831
14832 14832 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14833 14833 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14834 14834 did_pd->pd_port_id.port_id, did_pd->pd_state,
14835 14835
14836 14836 did_pd->pd_port_name.raw_wwn[0],
14837 14837 did_pd->pd_port_name.raw_wwn[1],
14838 14838 did_pd->pd_port_name.raw_wwn[2],
14839 14839 did_pd->pd_port_name.raw_wwn[3],
14840 14840 did_pd->pd_port_name.raw_wwn[4],
14841 14841 did_pd->pd_port_name.raw_wwn[5],
14842 14842 did_pd->pd_port_name.raw_wwn[6],
14843 14843 did_pd->pd_port_name.raw_wwn[7]);
14844 14844
14845 14845 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14846 14846 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14847 14847 mutex_exit(&did_pd->pd_mutex);
14848 14848 mutex_exit(&port->fp_mutex);
14849 14849
14850 14850 rval = fp_port_login(port, page->aff_d_id, job,
14851 14851 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14852 14852 if (rval == FC_SUCCESS) {
14853 14853 fp_jobwait(job);
14854 14854 if (job->job_result != FC_SUCCESS) {
14855 14855 fp_fillout_old_map(listptr +
14856 14856 *listindex - 1, did_pd, 0);
14857 14857 }
14858 14858 } else {
14859 14859 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14860 14860 }
14861 14861 } else {
14862 14862 mutex_exit(&did_pd->pd_mutex);
14863 14863 mutex_exit(&port->fp_mutex);
14864 14864 }
14865 14865
14866 14866 mutex_enter(&did_pd->pd_mutex);
14867 14867 did_pd->pd_flags = PD_IDLE;
14868 14868 mutex_exit(&did_pd->pd_mutex);
14869 14869 }
14870 14870
14871 14871
14872 14872 /*
14873 14873 * Check with NS for the presence of this port WWN
14874 14874 */
14875 14875 static int
14876 14876 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14877 14877 job_request_t *job, int polled, int sleep)
14878 14878 {
14879 14879 la_wwn_t pwwn;
14880 14880 uint32_t flags;
14881 14881 fctl_ns_req_t *ns_cmd;
14882 14882
14883 14883 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14884 14884 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14885 14885 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14886 14886 flags, sleep);
14887 14887 if (ns_cmd == NULL) {
14888 14888 return (FC_NOMEM);
14889 14889 }
14890 14890
14891 14891 mutex_enter(&pd->pd_mutex);
14892 14892 pwwn = pd->pd_port_name;
14893 14893 mutex_exit(&pd->pd_mutex);
14894 14894
14895 14895 ns_cmd->ns_cmd_code = NS_GID_PN;
14896 14896 ns_cmd->ns_pd = pd;
14897 14897 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14898 14898 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14899 14899 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14900 14900
14901 14901 return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14902 14902 }
14903 14903
14904 14904
14905 14905 /*
14906 14906 * Sanity check the LILP map returned by FCA
14907 14907 */
14908 14908 static int
14909 14909 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14910 14910 {
14911 14911 int count;
14912 14912
14913 14913 if (lilp_map->lilp_length == 0) {
14914 14914 return (FC_FAILURE);
14915 14915 }
14916 14916
14917 14917 for (count = 0; count < lilp_map->lilp_length; count++) {
14918 14918 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14919 14919 FC_SUCCESS) {
14920 14920 return (FC_FAILURE);
14921 14921 }
14922 14922 }
14923 14923
14924 14924 return (FC_SUCCESS);
14925 14925 }
14926 14926
14927 14927
14928 14928 /*
14929 14929 * Sanity check if the AL_PA is a valid address
14930 14930 */
14931 14931 static int
14932 14932 fp_is_valid_alpa(uchar_t al_pa)
14933 14933 {
14934 14934 int count;
14935 14935
14936 14936 for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14937 14937 if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14938 14938 return (FC_SUCCESS);
14939 14939 }
14940 14940 }
14941 14941
14942 14942 return (FC_FAILURE);
14943 14943 }
14944 14944
14945 14945
14946 14946 /*
14947 14947 * Post unsolicited callbacks to ULPs
14948 14948 */
14949 14949 static void
14950 14950 fp_ulp_unsol_cb(void *arg)
14951 14951 {
14952 14952 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg;
14953 14953
14954 14954 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14955 14955 ub_spec->buf->ub_frame.type);
14956 14956 kmem_free(ub_spec, sizeof (*ub_spec));
14957 14957 }
14958 14958
14959 14959
14960 14960 /*
14961 14961 * Perform message reporting in a consistent manner. Unless there is
14962 14962 * a strong reason NOT to use this function (which is very very rare)
14963 14963 * all message reporting should go through this.
14964 14964 */
14965 14965 static void
14966 14966 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14967 14967 fc_packet_t *pkt, const char *fmt, ...)
14968 14968 {
14969 14969 caddr_t buf;
14970 14970 va_list ap;
14971 14971
14972 14972 switch (level) {
14973 14973 case CE_NOTE:
14974 14974 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14975 14975 return;
14976 14976 }
14977 14977 break;
14978 14978
14979 14979 case CE_WARN:
14980 14980 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14981 14981 return;
14982 14982 }
14983 14983 break;
14984 14984 }
14985 14985
14986 14986 buf = kmem_zalloc(256, KM_NOSLEEP);
14987 14987 if (buf == NULL) {
14988 14988 return;
14989 14989 }
14990 14990
14991 14991 (void) sprintf(buf, "fp(%d): ", port->fp_instance);
14992 14992
14993 14993 va_start(ap, fmt);
14994 14994 (void) vsprintf(buf + strlen(buf), fmt, ap);
14995 14995 va_end(ap);
14996 14996
14997 14997 if (fc_errno) {
14998 14998 char *errmsg;
14999 14999
15000 15000 (void) fc_ulp_error(fc_errno, &errmsg);
15001 15001 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
15002 15002 } else {
15003 15003 if (pkt) {
15004 15004 caddr_t state, reason, action, expln;
15005 15005
15006 15006 (void) fc_ulp_pkt_error(pkt, &state, &reason,
15007 15007 &action, &expln);
15008 15008
15009 15009 (void) sprintf(buf + strlen(buf),
15010 15010 " state=%s, reason=%s", state, reason);
15011 15011
15012 15012 if (pkt->pkt_resp_resid) {
15013 15013 (void) sprintf(buf + strlen(buf),
15014 15014 " resp resid=%x\n", pkt->pkt_resp_resid);
15015 15015 }
15016 15016 }
15017 15017 }
15018 15018
15019 15019 switch (dest) {
15020 15020 case FP_CONSOLE_ONLY:
15021 15021 cmn_err(level, "^%s", buf);
15022 15022 break;
15023 15023
15024 15024 case FP_LOG_ONLY:
15025 15025 cmn_err(level, "!%s", buf);
15026 15026 break;
15027 15027
15028 15028 default:
15029 15029 cmn_err(level, "%s", buf);
15030 15030 break;
15031 15031 }
15032 15032
15033 15033 kmem_free(buf, 256);
15034 15034 }
15035 15035
15036 15036 static int
15037 15037 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15038 15038 {
15039 15039 int ret;
15040 15040 uint32_t d_id;
15041 15041 la_wwn_t pwwn;
15042 15042 fc_remote_port_t *pd = NULL;
15043 15043 fc_remote_port_t *held_pd = NULL;
15044 15044 fctl_ns_req_t *ns_cmd;
15045 15045 fc_portmap_t *changelist;
15046 15046
15047 15047 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15048 15048
15049 15049 mutex_enter(&port->fp_mutex);
15050 15050 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15051 15051 mutex_exit(&port->fp_mutex);
15052 15052 job->job_counter = 1;
15053 15053
15054 15054 job->job_result = FC_SUCCESS;
15055 15055
15056 15056 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
15057 15057 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
15058 15058 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
15059 15059
15060 15060 ASSERT(ns_cmd != NULL);
15061 15061
15062 15062 ns_cmd->ns_cmd_code = NS_GID_PN;
15063 15063 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
15064 15064
15065 15065 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
15066 15066
15067 15067 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15068 15068 if (ret != FC_SUCCESS) {
15069 15069 fcio->fcio_errno = ret;
15070 15070 } else {
15071 15071 fcio->fcio_errno = job->job_result;
15072 15072 }
15073 15073 fctl_free_ns_cmd(ns_cmd);
15074 15074 return (EIO);
15075 15075 }
15076 15076 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15077 15077 fctl_free_ns_cmd(ns_cmd);
15078 15078 } else {
15079 15079 mutex_exit(&port->fp_mutex);
15080 15080
15081 15081 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15082 15082 if (held_pd == NULL) {
15083 15083 fcio->fcio_errno = FC_BADWWN;
15084 15084 return (EIO);
15085 15085 }
15086 15086 pd = held_pd;
15087 15087
15088 15088 mutex_enter(&pd->pd_mutex);
15089 15089 d_id = pd->pd_port_id.port_id;
15090 15090 mutex_exit(&pd->pd_mutex);
15091 15091 }
15092 15092
15093 15093 job->job_counter = 1;
15094 15094
15095 15095 pd = fctl_get_remote_port_by_did(port, d_id);
15096 15096
15097 15097 if (pd) {
15098 15098 mutex_enter(&pd->pd_mutex);
15099 15099 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15100 15100 pd->pd_login_count++;
15101 15101 mutex_exit(&pd->pd_mutex);
15102 15102
15103 15103 fcio->fcio_errno = FC_SUCCESS;
15104 15104 if (held_pd) {
15105 15105 fctl_release_remote_port(held_pd);
15106 15106 }
15107 15107
15108 15108 return (0);
15109 15109 }
15110 15110 mutex_exit(&pd->pd_mutex);
15111 15111 } else {
15112 15112 mutex_enter(&port->fp_mutex);
15113 15113 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15114 15114 mutex_exit(&port->fp_mutex);
15115 15115 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15116 15116 if (pd == NULL) {
15117 15117 fcio->fcio_errno = FC_FAILURE;
15118 15118 if (held_pd) {
15119 15119 fctl_release_remote_port(held_pd);
15120 15120 }
15121 15121 return (EIO);
15122 15122 }
15123 15123 } else {
15124 15124 mutex_exit(&port->fp_mutex);
15125 15125 }
15126 15126 }
15127 15127
15128 15128 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15129 15129 job->job_counter = 1;
15130 15130
15131 15131 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15132 15132 KM_SLEEP, pd, NULL);
15133 15133
15134 15134 if (ret != FC_SUCCESS) {
15135 15135 fcio->fcio_errno = ret;
15136 15136 if (held_pd) {
15137 15137 fctl_release_remote_port(held_pd);
15138 15138 }
15139 15139 return (EIO);
15140 15140 }
15141 15141 fp_jobwait(job);
15142 15142
15143 15143 fcio->fcio_errno = job->job_result;
15144 15144
15145 15145 if (held_pd) {
15146 15146 fctl_release_remote_port(held_pd);
15147 15147 }
15148 15148
15149 15149 if (job->job_result != FC_SUCCESS) {
15150 15150 return (EIO);
15151 15151 }
15152 15152
15153 15153 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15154 15154 if (pd == NULL) {
15155 15155 fcio->fcio_errno = FC_BADDEV;
15156 15156 return (ENODEV);
15157 15157 }
15158 15158
15159 15159 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15160 15160
15161 15161 fctl_copy_portmap(changelist, pd);
15162 15162 changelist->map_type = PORT_DEVICE_USER_LOGIN;
15163 15163
15164 15164 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15165 15165
15166 15166 mutex_enter(&pd->pd_mutex);
15167 15167 pd->pd_type = PORT_DEVICE_NOCHANGE;
15168 15168 mutex_exit(&pd->pd_mutex);
15169 15169
15170 15170 fctl_release_remote_port(pd);
15171 15171
15172 15172 return (0);
15173 15173 }
15174 15174
15175 15175
15176 15176 static int
15177 15177 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15178 15178 {
15179 15179 la_wwn_t pwwn;
15180 15180 fp_cmd_t *cmd;
15181 15181 fc_portmap_t *changelist;
15182 15182 fc_remote_port_t *pd;
15183 15183
15184 15184 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15185 15185
15186 15186 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15187 15187 if (pd == NULL) {
15188 15188 fcio->fcio_errno = FC_BADWWN;
15189 15189 return (ENXIO);
15190 15190 }
15191 15191
15192 15192 mutex_enter(&pd->pd_mutex);
15193 15193 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15194 15194 fcio->fcio_errno = FC_LOGINREQ;
15195 15195 mutex_exit(&pd->pd_mutex);
15196 15196
15197 15197 fctl_release_remote_port(pd);
15198 15198
15199 15199 return (EINVAL);
15200 15200 }
15201 15201
15202 15202 ASSERT(pd->pd_login_count >= 1);
15203 15203
15204 15204 if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15205 15205 fcio->fcio_errno = FC_FAILURE;
15206 15206 mutex_exit(&pd->pd_mutex);
15207 15207
15208 15208 fctl_release_remote_port(pd);
15209 15209
15210 15210 return (EBUSY);
15211 15211 }
15212 15212
15213 15213 if (pd->pd_login_count > 1) {
15214 15214 pd->pd_login_count--;
15215 15215 fcio->fcio_errno = FC_SUCCESS;
15216 15216 mutex_exit(&pd->pd_mutex);
15217 15217
15218 15218 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15219 15219
15220 15220 fctl_copy_portmap(changelist, pd);
15221 15221 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15222 15222
15223 15223 fctl_release_remote_port(pd);
15224 15224
15225 15225 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15226 15226
15227 15227 return (0);
15228 15228 }
15229 15229
15230 15230 pd->pd_flags = PD_ELS_IN_PROGRESS;
15231 15231 mutex_exit(&pd->pd_mutex);
15232 15232
15233 15233 job->job_counter = 1;
15234 15234
15235 15235 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15236 15236 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15237 15237 if (cmd == NULL) {
15238 15238 fcio->fcio_errno = FC_NOMEM;
15239 15239 fctl_release_remote_port(pd);
15240 15240
15241 15241 mutex_enter(&pd->pd_mutex);
15242 15242 pd->pd_flags = PD_IDLE;
15243 15243 mutex_exit(&pd->pd_mutex);
15244 15244
15245 15245 return (ENOMEM);
15246 15246 }
15247 15247
15248 15248 mutex_enter(&port->fp_mutex);
15249 15249 mutex_enter(&pd->pd_mutex);
15250 15250
15251 15251 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15252 15252 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15253 15253 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15254 15254 cmd->cmd_retry_count = 1;
15255 15255 cmd->cmd_ulp_pkt = NULL;
15256 15256
15257 15257 fp_logo_init(pd, cmd, job);
15258 15258
15259 15259 mutex_exit(&pd->pd_mutex);
15260 15260 mutex_exit(&port->fp_mutex);
15261 15261
15262 15262 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15263 15263 mutex_enter(&pd->pd_mutex);
15264 15264 pd->pd_flags = PD_IDLE;
15265 15265 mutex_exit(&pd->pd_mutex);
15266 15266
15267 15267 fp_free_pkt(cmd);
15268 15268 fctl_release_remote_port(pd);
15269 15269
15270 15270 return (EIO);
15271 15271 }
15272 15272
15273 15273 fp_jobwait(job);
15274 15274
15275 15275 fcio->fcio_errno = job->job_result;
15276 15276 if (job->job_result != FC_SUCCESS) {
15277 15277 mutex_enter(&pd->pd_mutex);
15278 15278 pd->pd_flags = PD_IDLE;
15279 15279 mutex_exit(&pd->pd_mutex);
15280 15280
15281 15281 fctl_release_remote_port(pd);
15282 15282
15283 15283 return (EIO);
15284 15284 }
15285 15285
15286 15286 ASSERT(pd != NULL);
15287 15287
15288 15288 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15289 15289
15290 15290 fctl_copy_portmap(changelist, pd);
15291 15291 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15292 15292 changelist->map_state = PORT_DEVICE_INVALID;
15293 15293
15294 15294 mutex_enter(&port->fp_mutex);
15295 15295 mutex_enter(&pd->pd_mutex);
15296 15296
15297 15297 fctl_delist_did_table(port, pd);
15298 15298 fctl_delist_pwwn_table(port, pd);
15299 15299 pd->pd_flags = PD_IDLE;
15300 15300
15301 15301 mutex_exit(&pd->pd_mutex);
15302 15302 mutex_exit(&port->fp_mutex);
15303 15303
15304 15304 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15305 15305
15306 15306 fctl_release_remote_port(pd);
15307 15307
15308 15308 return (0);
15309 15309 }
15310 15310
15311 15311
15312 15312
15313 15313 /*
15314 15314 * Send a syslog event for adapter port level events.
15315 15315 */
15316 15316 static void
15317 15317 fp_log_port_event(fc_local_port_t *port, char *subclass)
15318 15318 {
15319 15319 nvlist_t *attr_list;
15320 15320
15321 15321 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15322 15322 KM_SLEEP) != DDI_SUCCESS) {
15323 15323 goto alloc_failed;
15324 15324 }
15325 15325
15326 15326 if (nvlist_add_uint32(attr_list, "instance",
15327 15327 port->fp_instance) != DDI_SUCCESS) {
15328 15328 goto error;
15329 15329 }
15330 15330
15331 15331 if (nvlist_add_byte_array(attr_list, "port-wwn",
15332 15332 port->fp_service_params.nport_ww_name.raw_wwn,
15333 15333 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15334 15334 goto error;
15335 15335 }
15336 15336
15337 15337 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15338 15338 subclass, attr_list, NULL, DDI_SLEEP);
15339 15339
15340 15340 nvlist_free(attr_list);
15341 15341 return;
15342 15342
15343 15343 error:
15344 15344 nvlist_free(attr_list);
15345 15345 alloc_failed:
15346 15346 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15347 15347 }
15348 15348
15349 15349
15350 15350 static void
15351 15351 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15352 15352 uint32_t port_id)
15353 15353 {
15354 15354 nvlist_t *attr_list;
15355 15355
15356 15356 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15357 15357 KM_SLEEP) != DDI_SUCCESS) {
15358 15358 goto alloc_failed;
15359 15359 }
15360 15360
15361 15361 if (nvlist_add_uint32(attr_list, "instance",
15362 15362 port->fp_instance) != DDI_SUCCESS) {
15363 15363 goto error;
15364 15364 }
15365 15365
15366 15366 if (nvlist_add_byte_array(attr_list, "port-wwn",
15367 15367 port->fp_service_params.nport_ww_name.raw_wwn,
15368 15368 sizeof (la_wwn_t)) != DDI_SUCCESS) {
15369 15369 goto error;
15370 15370 }
15371 15371
15372 15372 if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15373 15373 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15374 15374 goto error;
15375 15375 }
15376 15376
15377 15377 if (nvlist_add_uint32(attr_list, "target-port-id",
15378 15378 port_id) != DDI_SUCCESS) {
15379 15379 goto error;
15380 15380 }
15381 15381
15382 15382 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15383 15383 subclass, attr_list, NULL, DDI_SLEEP);
15384 15384
15385 15385 nvlist_free(attr_list);
15386 15386 return;
15387 15387
15388 15388 error:
15389 15389 nvlist_free(attr_list);
15390 15390 alloc_failed:
15391 15391 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15392 15392 }
15393 15393
15394 15394 static uint32_t
15395 15395 fp_map_remote_port_state(uint32_t rm_state)
15396 15396 {
15397 15397 switch (rm_state) {
15398 15398 case PORT_DEVICE_LOGGED_IN:
15399 15399 return (FC_HBA_PORTSTATE_ONLINE);
15400 15400 case PORT_DEVICE_VALID:
15401 15401 case PORT_DEVICE_INVALID:
15402 15402 default:
15403 15403 return (FC_HBA_PORTSTATE_UNKNOWN);
15404 15404 }
15405 15405 }
↓ open down ↓ |
13704 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX