Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/comstar/port/fct/fct.c
+++ new/usr/src/uts/common/io/comstar/port/fct/fct.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 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <sys/conf.h>
27 27 #include <sys/file.h>
28 28 #include <sys/ddi.h>
29 29 #include <sys/sunddi.h>
30 30 #include <sys/modctl.h>
31 31 #include <sys/scsi/scsi.h>
32 32 #include <sys/scsi/impl/scsi_reset_notify.h>
33 33 #include <sys/disp.h>
34 34 #include <sys/byteorder.h>
35 35 #include <sys/varargs.h>
36 36 #include <sys/atomic.h>
37 37 #include <sys/sdt.h>
38 38
39 39 #include <sys/stmf.h>
40 40 #include <sys/stmf_ioctl.h>
41 41 #include <sys/portif.h>
42 42 #include <sys/fct.h>
43 43 #include <sys/fctio.h>
44 44
45 45 #include "fct_impl.h"
46 46 #include "discovery.h"
47 47
48 48 static int fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
49 49 static int fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
50 50 static int fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
51 51 void **result);
52 52 static int fct_open(dev_t *devp, int flag, int otype, cred_t *credp);
53 53 static int fct_close(dev_t dev, int flag, int otype, cred_t *credp);
54 54 static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
55 55 cred_t *credp, int *rval);
56 56 static int fct_fctiocmd(intptr_t data, int mode);
57 57 void fct_init_kstats(fct_i_local_port_t *iport);
58 58
59 59 static dev_info_t *fct_dip;
60 60 static struct cb_ops fct_cb_ops = {
61 61 fct_open, /* open */
62 62 fct_close, /* close */
63 63 nodev, /* strategy */
64 64 nodev, /* print */
65 65 nodev, /* dump */
66 66 nodev, /* read */
67 67 nodev, /* write */
68 68 fct_ioctl, /* ioctl */
69 69 nodev, /* devmap */
70 70 nodev, /* mmap */
71 71 nodev, /* segmap */
72 72 nochpoll, /* chpoll */
73 73 ddi_prop_op, /* cb_prop_op */
74 74 0, /* streamtab */
75 75 D_NEW | D_MP, /* cb_flag */
76 76 CB_REV, /* rev */
77 77 nodev, /* aread */
78 78 nodev /* awrite */
79 79 };
80 80
81 81 static struct dev_ops fct_ops = {
82 82 DEVO_REV,
83 83 0,
84 84 fct_getinfo,
85 85 nulldev, /* identify */
86 86 nulldev, /* probe */
87 87 fct_attach,
88 88 fct_detach,
89 89 nodev, /* reset */
90 90 &fct_cb_ops,
91 91 NULL, /* bus_ops */
92 92 NULL /* power */
93 93 };
94 94
95 95 #define FCT_NAME "COMSTAR FCT"
96 96 #define FCT_MODULE_NAME "fct"
↓ open down ↓ |
96 lines elided |
↑ open up ↑ |
97 97
98 98 extern struct mod_ops mod_driverops;
99 99 static struct modldrv modldrv = {
100 100 &mod_driverops,
101 101 FCT_NAME,
102 102 &fct_ops
103 103 };
104 104
105 105 static struct modlinkage modlinkage = {
106 106 MODREV_1,
107 - &modldrv,
108 - NULL
107 + { &modldrv, NULL }
109 108 };
110 109
111 110 static uint32_t rportid_table_size = FCT_HASH_TABLE_SIZE;
112 111 static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
113 112 static fct_i_local_port_t *fct_iport_list = NULL;
114 113 static kmutex_t fct_global_mutex;
115 114 uint32_t fct_rscn_options = RSCN_OPTION_VERIFY;
116 115
117 116 int
118 117 _init(void)
119 118 {
120 119 int ret;
121 120
122 121 ret = mod_install(&modlinkage);
123 122 if (ret)
124 123 return (ret);
125 124 /* XXX */
126 125 mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL);
127 126 return (ret);
128 127 }
129 128
130 129 int
131 130 _fini(void)
132 131 {
133 132 int ret;
134 133
135 134 ret = mod_remove(&modlinkage);
136 135 if (ret)
137 136 return (ret);
138 137 /* XXX */
139 138 mutex_destroy(&fct_global_mutex);
140 139 return (ret);
141 140 }
142 141
143 142 int
144 143 _info(struct modinfo *modinfop)
145 144 {
146 145 return (mod_info(&modlinkage, modinfop));
147 146 }
148 147
149 148 /* ARGSUSED */
150 149 static int
151 150 fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
152 151 {
153 152 switch (cmd) {
154 153 case DDI_INFO_DEVT2DEVINFO:
155 154 *result = fct_dip;
156 155 break;
157 156 case DDI_INFO_DEVT2INSTANCE:
158 157 *result = (void *)(uintptr_t)ddi_get_instance(fct_dip);
159 158 break;
160 159 default:
161 160 return (DDI_FAILURE);
162 161 }
163 162
164 163 return (DDI_SUCCESS);
165 164 }
166 165
167 166 static int
168 167 fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
169 168 {
170 169 switch (cmd) {
171 170 case DDI_ATTACH:
172 171 fct_dip = dip;
173 172
174 173 if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
175 174 DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
176 175 break;
177 176 }
178 177 ddi_report_dev(dip);
179 178 return (DDI_SUCCESS);
180 179 }
181 180
182 181 return (DDI_FAILURE);
183 182 }
184 183
185 184 static int
186 185 fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
187 186 {
188 187 switch (cmd) {
189 188 case DDI_DETACH:
190 189 ddi_remove_minor_node(dip, 0);
191 190 return (DDI_SUCCESS);
192 191 }
193 192
194 193 return (DDI_FAILURE);
195 194 }
196 195
197 196 /* ARGSUSED */
198 197 static int
199 198 fct_open(dev_t *devp, int flag, int otype, cred_t *credp)
200 199 {
201 200 if (otype != OTYP_CHR)
202 201 return (EINVAL);
203 202 return (0);
204 203 }
205 204
206 205 /* ARGSUSED */
207 206 static int
208 207 fct_close(dev_t dev, int flag, int otype, cred_t *credp)
209 208 {
210 209 return (0);
211 210 }
212 211
213 212 /* ARGSUSED */
214 213 static int
215 214 fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
216 215 cred_t *credp, int *rval)
217 216 {
218 217 int ret = 0;
219 218
220 219 if ((cmd & 0xff000000) != FCT_IOCTL) {
221 220 return (ENOTTY);
222 221 }
223 222
224 223 if (drv_priv(credp) != 0) {
225 224 return (EPERM);
226 225 }
227 226
228 227 switch (cmd) {
229 228 case FCTIO_CMD:
230 229 ret = fct_fctiocmd(data, mode);
231 230 break;
232 231 default:
233 232 ret = ENOTTY;
234 233 break;
235 234 }
236 235
237 236 return (ret);
238 237 }
239 238
240 239 int
241 240 fct_copyin_iocdata(intptr_t data, int mode, fctio_t **fctio,
242 241 void **ibuf, void **abuf, void **obuf)
243 242 {
244 243 int ret = 0;
245 244
246 245 *ibuf = NULL;
247 246 *abuf = NULL;
248 247 *obuf = NULL;
249 248 *fctio = kmem_zalloc(sizeof (fctio_t), KM_SLEEP);
250 249 if (ddi_copyin((void *)data, *fctio, sizeof (fctio_t), mode)) {
251 250 ret = EFAULT;
252 251 goto copyin_iocdata_done;
253 252 }
254 253
255 254 if ((*fctio)->fctio_ilen) {
256 255 *ibuf = kmem_zalloc((*fctio)->fctio_ilen, KM_SLEEP);
257 256 if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_ibuf,
258 257 *ibuf, (*fctio)->fctio_ilen, mode)) {
259 258 ret = EFAULT;
260 259 goto copyin_iocdata_done;
261 260 }
262 261 }
263 262 if ((*fctio)->fctio_alen) {
264 263 *abuf = kmem_zalloc((*fctio)->fctio_alen, KM_SLEEP);
265 264 if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_abuf,
266 265 *abuf, (*fctio)->fctio_alen, mode)) {
267 266 ret = EFAULT;
268 267 goto copyin_iocdata_done;
269 268 }
270 269 }
271 270 if ((*fctio)->fctio_olen)
272 271 *obuf = kmem_zalloc((*fctio)->fctio_olen, KM_SLEEP);
273 272 if (ret == 0)
274 273 return (0);
275 274 ret = EFAULT;
276 275 copyin_iocdata_done:
277 276 if (*obuf) {
278 277 kmem_free(*obuf, (*fctio)->fctio_olen);
279 278 *obuf = NULL;
280 279 }
281 280 if (*abuf) {
282 281 kmem_free(*abuf, (*fctio)->fctio_alen);
283 282 *abuf = NULL;
284 283 }
285 284 if (*ibuf) {
286 285 kmem_free(*ibuf, (*fctio)->fctio_ilen);
287 286 *ibuf = NULL;
288 287 }
289 288 kmem_free(*fctio, sizeof (fctio_t));
290 289 return (ret);
291 290 }
292 291
293 292 int
294 293 fct_copyout_iocdata(intptr_t data, int mode, fctio_t *fctio, void *obuf)
295 294 {
296 295 int ret = 0;
297 296
298 297 if (fctio->fctio_olen) {
299 298 ret = ddi_copyout(obuf,
300 299 (void *)(unsigned long)fctio->fctio_obuf, fctio->fctio_olen,
301 300 mode);
302 301 if (ret) {
303 302 return (EFAULT);
304 303 }
305 304 }
306 305 ret = ddi_copyout(fctio, (void *)data, sizeof (fctio_t), mode);
307 306 if (ret) {
308 307 return (EFAULT);
309 308 }
310 309 return (0);
311 310 }
312 311
313 312 int
314 313 fct_get_port_list(char *pathList, int count)
315 314 {
316 315 fct_i_local_port_t *iport;
317 316 int i = 0, maxPorts = 0;
318 317
319 318 ASSERT(pathList != NULL);
320 319
321 320 mutex_enter(&fct_global_mutex);
322 321 for (iport = fct_iport_list; iport; iport = iport->iport_next) {
323 322 if (i < count)
324 323 bcopy(iport->iport_port->port_pwwn,
325 324 pathList + 8 * i, 8);
326 325 maxPorts ++;
327 326 i++;
328 327 }
329 328 mutex_exit(&fct_global_mutex);
330 329 return (maxPorts);
331 330 }
332 331
333 332 /* invoked with fct_global_mutex locked */
334 333 fct_i_local_port_t *
335 334 fct_get_iport_per_wwn(uint8_t *pwwn)
336 335 {
337 336 fct_i_local_port_t *iport;
338 337
339 338 ASSERT(mutex_owned(&fct_global_mutex));
340 339 for (iport = fct_iport_list; iport; iport = iport->iport_next) {
341 340 if (bcmp(iport->iport_port->port_pwwn, pwwn, 8) == 0)
342 341 return (iport);
343 342 }
344 343 return (NULL);
345 344 }
346 345
347 346 int
348 347 fct_get_adapter_attr(uint8_t *pwwn, fc_tgt_hba_adapter_attributes_t *hba_attr,
349 348 uint32_t *err_detail)
350 349 {
351 350 fct_i_local_port_t *iport;
352 351 fct_port_attrs_t *attr;
353 352
354 353 hba_attr->version = FCT_HBA_ADAPTER_ATTRIBUTES_VERSION;
355 354 iport = fct_get_iport_per_wwn(pwwn);
356 355 if (!iport) {
357 356 *err_detail = FCTIO_BADWWN;
358 357 return (ENXIO);
359 358 }
360 359
361 360 attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
362 361 KM_SLEEP);
363 362 mutex_exit(&fct_global_mutex);
364 363 iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
365 364 mutex_enter(&fct_global_mutex);
366 365
367 366 bcopy(attr->manufacturer, hba_attr->Manufacturer,
368 367 sizeof (hba_attr->Manufacturer));
369 368 bcopy(attr->serial_number, hba_attr->SerialNumber,
370 369 sizeof (hba_attr->SerialNumber));
371 370 bcopy(attr->model, hba_attr->Model, sizeof (hba_attr->Model));
372 371 bcopy(attr->model_description, hba_attr->ModelDescription,
373 372 sizeof (hba_attr->ModelDescription));
374 373 if (iport->iport_port->port_sym_node_name)
375 374 bcopy(iport->iport_port->port_sym_node_name,
376 375 hba_attr->NodeSymbolicName,
377 376 strlen(iport->iport_port->port_sym_node_name));
378 377 else
379 378 bcopy(utsname.nodename, hba_attr->NodeSymbolicName,
380 379 strlen(utsname.nodename));
381 380 bcopy(attr->hardware_version, hba_attr->HardwareVersion,
382 381 sizeof (hba_attr->HardwareVersion));
383 382 bcopy(attr->option_rom_version, hba_attr->OptionROMVersion,
384 383 sizeof (hba_attr->OptionROMVersion));
385 384 bcopy(attr->firmware_version, hba_attr->FirmwareVersion,
386 385 sizeof (hba_attr->FirmwareVersion));
387 386 hba_attr->VendorSpecificID = attr->vendor_specific_id;
388 387 bcopy(iport->iport_port->port_nwwn, hba_attr->NodeWWN,
389 388 sizeof (hba_attr->NodeWWN));
390 389
391 390 bcopy(attr->driver_name, hba_attr->DriverName,
392 391 sizeof (hba_attr->DriverName));
393 392 bcopy(attr->driver_version, hba_attr->DriverVersion,
394 393 sizeof (hba_attr->DriverVersion));
395 394
396 395
397 396 /* hba_attr->NumberOfPorts = fct_count_fru_ports(iport); */
398 397 hba_attr->NumberOfPorts = 1;
399 398
400 399 kmem_free(attr, sizeof (fct_port_attrs_t));
401 400 return (0);
402 401 }
403 402
404 403 int
405 404 fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn,
406 405 fc_tgt_hba_port_attributes_t *port_attr, uint32_t *err_detail)
407 406 {
408 407 fct_i_local_port_t *iport = ilport;
409 408 fct_i_remote_port_t *irp = NULL;
410 409 fct_port_attrs_t *attr;
411 410 int i = 0;
412 411
413 412 port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
414 413
415 414 if (!ilport) {
416 415 iport = fct_get_iport_per_wwn(pwwn);
417 416 if (!iport) {
418 417 *err_detail = FCTIO_BADWWN;
419 418 return (ENXIO);
420 419 }
421 420 }
422 421
423 422 attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
424 423 KM_SLEEP);
425 424 mutex_exit(&fct_global_mutex);
426 425 iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
427 426 mutex_enter(&fct_global_mutex);
428 427
429 428 port_attr->lastChange = iport->iport_last_change;
430 429 bcopy(iport->iport_port->port_nwwn, port_attr->NodeWWN,
431 430 sizeof (port_attr->NodeWWN));
432 431 bcopy(iport->iport_port->port_pwwn, port_attr->PortWWN,
433 432 sizeof (port_attr->PortWWN));
434 433 bzero(port_attr->FabricName, sizeof (port_attr->FabricName));
435 434 port_attr->PortFcId = iport->iport_link_info.portid;
436 435 if ((iport->iport_link_state & S_LINK_ONLINE) ||
437 436 (iport->iport_link_state & S_RCVD_LINK_UP)) {
438 437 port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
439 438 } else {
440 439 port_attr->PortState = FC_HBA_PORTSTATE_OFFLINE;
441 440 }
442 441 switch (iport->iport_link_info.port_topology) {
443 442 case PORT_TOPOLOGY_PT_TO_PT:
444 443 port_attr->PortType = FC_HBA_PORTTYPE_PTP;
445 444 break;
446 445 case PORT_TOPOLOGY_PRIVATE_LOOP:
447 446 port_attr->PortType = FC_HBA_PORTTYPE_LPORT;
448 447 break;
449 448 case PORT_TOPOLOGY_PUBLIC_LOOP:
450 449 port_attr->PortType = FC_HBA_PORTTYPE_NLPORT;
451 450 break;
452 451 case PORT_TOPOLOGY_FABRIC_PT_TO_PT:
453 452 port_attr->PortType = FC_HBA_PORTTYPE_FPORT;
454 453 break;
455 454 default:
456 455 port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
457 456 break;
458 457 }
459 458 port_attr->PortSupportedClassofService = attr->supported_cos;
460 459 port_attr->PortSupportedFc4Types[0] = 0;
461 460 port_attr->PortActiveFc4Types[2] = 1;
462 461 if (iport->iport_port->port_sym_port_name)
463 462 bcopy(iport->iport_port->port_sym_port_name,
464 463 port_attr->PortSymbolicName,
465 464 strlen(iport->iport_port->port_sym_port_name));
466 465 else if (iport->iport_port->port_default_alias)
467 466 bcopy(iport->iport_port->port_default_alias,
468 467 port_attr->PortSymbolicName,
469 468 strlen(iport->iport_port->port_default_alias));
470 469 else
471 470 port_attr->PortSymbolicName[0] = 0;
472 471 /* the definition is different so need to translate */
473 472 if (attr->supported_speed & PORT_SPEED_1G)
474 473 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT;
475 474 if (attr->supported_speed & PORT_SPEED_2G)
476 475 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT;
477 476 if (attr->supported_speed & PORT_SPEED_4G)
478 477 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT;
479 478 if (attr->supported_speed & PORT_SPEED_8G)
480 479 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT;
481 480 if (attr->supported_speed & PORT_SPEED_10G)
482 481 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT;
483 482 if (attr->supported_speed & PORT_SPEED_16G)
484 483 port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_16GBIT;
485 484 switch (iport->iport_link_info.port_speed) {
486 485 case PORT_SPEED_1G:
487 486 port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
488 487 break;
489 488 case PORT_SPEED_2G:
490 489 port_attr->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
491 490 break;
492 491 case PORT_SPEED_4G:
493 492 port_attr->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
494 493 break;
495 494 case PORT_SPEED_8G:
496 495 port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
497 496 break;
498 497 case PORT_SPEED_10G:
499 498 port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
500 499 break;
501 500 case PORT_SPEED_16G:
502 501 port_attr->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
503 502 break;
504 503 default:
505 504 port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
506 505 break;
507 506 }
508 507 port_attr->PortMaxFrameSize = attr->max_frame_size;
509 508 rw_enter(&iport->iport_lock, RW_READER);
510 509 port_attr->NumberofDiscoveredPorts = iport->iport_nrps_login;
511 510 for (; i < iport->iport_port->port_max_logins; i++) {
512 511 irp = iport->iport_rp_slots[i];
513 512 if (irp && irp->irp_flags & IRP_PLOGI_DONE) {
514 513 if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
515 514 port_attr->NumberofDiscoveredPorts --;
516 515 }
517 516 }
518 517 rw_exit(&iport->iport_lock);
519 518
520 519 kmem_free(attr, sizeof (fct_port_attrs_t));
521 520
522 521 return (0);
523 522 }
524 523
525 524 int
526 525 fct_get_discovered_port_attr(fct_i_remote_port_t *remote_port,
527 526 uint8_t *port_wwn, uint32_t index, fc_tgt_hba_port_attributes_t *port_attr,
528 527 uint32_t *error_detail)
529 528 {
530 529 fct_i_local_port_t *iport;
531 530 fct_i_remote_port_t *irp = remote_port;
532 531 int count = 0, i = 0;
533 532
534 533 port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
535 534 if (!remote_port) {
536 535 iport = fct_get_iport_per_wwn(port_wwn);
537 536 if (!iport) {
538 537 *error_detail = FCTIO_BADWWN;
539 538 return (ENXIO);
540 539 }
541 540
542 541 rw_enter(&iport->iport_lock, RW_READER);
543 542
544 543 if (index >= iport->iport_nrps_login) {
545 544 rw_exit(&iport->iport_lock);
546 545 *error_detail = FCTIO_OUTOFBOUNDS;
547 546 return (EINVAL);
548 547 }
549 548 for (; i < iport->iport_port->port_max_logins; i++) {
550 549 irp = iport->iport_rp_slots[i];
551 550 if (irp && irp->irp_flags & IRP_PLOGI_DONE &&
552 551 !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
553 552 count ++;
554 553 if ((index + 1) <= count)
555 554 break;
556 555 }
557 556 }
558 557 if (i >= iport->iport_port->port_max_logins) {
559 558 rw_exit(&iport->iport_lock);
560 559 *error_detail = FCTIO_OUTOFBOUNDS;
561 560 return (EINVAL);
562 561 }
563 562 ASSERT(irp);
564 563 } else {
565 564 iport = (fct_i_local_port_t *)
566 565 irp->irp_rp->rp_port->port_fct_private;
567 566 }
568 567 port_attr->lastChange = iport->iport_last_change;
569 568 rw_enter(&irp->irp_lock, RW_READER);
570 569 bcopy(irp->irp_rp->rp_pwwn, port_attr->PortWWN,
571 570 sizeof (port_attr->PortWWN));
572 571 bcopy(irp->irp_rp->rp_nwwn, port_attr->NodeWWN,
573 572 sizeof (port_attr->NodeWWN));
574 573 port_attr->PortFcId = irp->irp_portid;
575 574 if (irp->irp_spn)
576 575 (void) strncpy(port_attr->PortSymbolicName, irp->irp_spn,
577 576 strlen(irp->irp_spn));
578 577 else
579 578 port_attr->PortSymbolicName[0] = '\0';
580 579 port_attr->PortSupportedClassofService = irp->irp_cos;
581 580 bcopy((caddr_t)irp->irp_fc4types, port_attr->PortActiveFc4Types,
582 581 sizeof (irp->irp_fc4types));
583 582 bcopy((caddr_t)irp->irp_fc4types, port_attr->PortSupportedFc4Types,
584 583 sizeof (irp->irp_fc4types));
585 584 if (irp->irp_flags & IRP_PLOGI_DONE)
586 585 port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
587 586 else
588 587 port_attr->PortState = FC_HBA_PORTSTATE_UNKNOWN;
589 588
590 589 port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
591 590 port_attr->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
592 591 port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
593 592 port_attr->PortMaxFrameSize = 0;
594 593 port_attr->NumberofDiscoveredPorts = 0;
595 594 rw_exit(&irp->irp_lock);
596 595 if (!remote_port) {
597 596 rw_exit(&iport->iport_lock);
598 597 }
599 598 return (0);
600 599 }
601 600
602 601 int
603 602 fct_get_port_attr(uint8_t *port_wwn,
604 603 fc_tgt_hba_port_attributes_t *port_attr, uint32_t *error_detail)
605 604 {
606 605 fct_i_local_port_t *iport;
607 606 fct_i_remote_port_t *irp;
608 607 int i, ret;
609 608
610 609 iport = fct_get_iport_per_wwn(port_wwn);
611 610 if (iport) {
612 611 return (fct_get_adapter_port_attr(iport, port_wwn,
613 612 port_attr, error_detail));
614 613 }
615 614 /* else */
616 615 for (iport = fct_iport_list; iport; iport = iport->iport_next) {
617 616 rw_enter(&iport->iport_lock, RW_READER);
618 617 for (i = 0; i < rportid_table_size; i++) {
619 618 irp = iport->iport_rp_tb[i];
620 619 while (irp) {
621 620 if (bcmp(irp->irp_rp->rp_pwwn,
622 621 port_wwn, 8) == 0 &&
623 622 irp->irp_flags & IRP_PLOGI_DONE) {
624 623 ret = fct_get_discovered_port_attr(
625 624 irp, NULL, 0, port_attr,
626 625 error_detail);
627 626 rw_exit(&iport->iport_lock);
628 627 return (ret);
629 628 }
630 629 irp = irp->irp_next;
631 630 }
632 631 }
633 632 rw_exit(&iport->iport_lock);
634 633 }
635 634 *error_detail = FCTIO_BADWWN;
636 635 return (ENXIO);
637 636 }
638 637
639 638 /* ARGSUSED */
640 639 int
641 640 fct_get_port_stats(uint8_t *port_wwn,
642 641 fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail)
643 642 {
644 643 int ret;
645 644 fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
646 645 fct_port_link_status_t stat;
647 646 uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t);
648 647
649 648 if (!iport)
650 649 return (ENXIO);
651 650 port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION;
652 651
653 652 if (iport->iport_port->port_info == NULL) {
654 653 *error_detail = FCTIO_FAILURE;
655 654 return (EIO);
656 655 }
657 656 ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
658 657 iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
659 658 if (ret != STMF_SUCCESS) {
660 659 *error_detail = FCTIO_FAILURE;
661 660 return (EIO);
662 661 }
663 662
664 663 port_stats->SecondsSinceLastReset = 0;
665 664 port_stats->TxFrames = 0;
666 665 port_stats->TxWords = 0;
667 666 port_stats->RxFrames = 0;
668 667 port_stats->RxWords = 0;
669 668 port_stats->LIPCount = 0;
670 669 port_stats->NOSCount = 0;
671 670 port_stats->ErrorFrames = 0;
672 671 port_stats->DumpedFrames = 0;
673 672 port_stats->LinkFailureCount = stat.LinkFailureCount;
674 673 port_stats->LossOfSyncCount = stat.LossOfSyncCount;
675 674 port_stats->LossOfSignalCount = stat.LossOfSignalsCount;
676 675 port_stats->PrimitiveSeqProtocolErrCount =
677 676 stat.PrimitiveSeqProtocolErrorCount;
678 677 port_stats->InvalidTxWordCount =
679 678 stat.InvalidTransmissionWordCount;
680 679 port_stats->InvalidCRCCount = stat.InvalidCRCCount;
681 680
682 681 return (ret);
683 682 }
684 683
685 684 int
686 685 fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id,
687 686 fct_port_link_status_t *link_status, uint32_t *error_detail)
688 687 {
689 688 fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
690 689 fct_i_remote_port_t *irp = NULL;
691 690 uint32_t buf_size = sizeof (fct_port_link_status_t);
692 691 stmf_status_t ret = 0;
693 692 int i;
694 693 fct_cmd_t *cmd = NULL;
695 694
696 695 if (!iport) {
697 696 *error_detail = FCTIO_BADWWN;
698 697 return (ENXIO);
699 698 }
700 699
701 700 /*
702 701 * If what we are requesting is zero or same as local port,
703 702 * then we use port_info()
704 703 */
705 704 if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) {
706 705 if (iport->iport_port->port_info == NULL) {
707 706 *error_detail = FCTIO_FAILURE;
708 707 return (EIO);
709 708 }
710 709 ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
711 710 iport->iport_port, NULL,
712 711 (uint8_t *)link_status, &buf_size);
713 712 if (ret == STMF_SUCCESS) {
714 713 return (0);
715 714 } else {
716 715 *error_detail = FCTIO_FAILURE;
717 716 return (EIO);
718 717 }
719 718 }
720 719
721 720 /*
722 721 * For remote port, we will send RLS
723 722 */
724 723 for (i = 0; i < rportid_table_size; i++) {
725 724 irp = iport->iport_rp_tb[i];
726 725 while (irp) {
727 726 if (irp->irp_rp->rp_id == *dest_id &&
728 727 irp->irp_flags & IRP_PLOGI_DONE) {
729 728 goto SEND_RLS_ELS;
730 729 }
731 730 irp = irp->irp_next;
732 731 }
733 732 }
734 733 return (ENXIO);
735 734
736 735 SEND_RLS_ELS:
737 736 cmd = fct_create_solels(iport->iport_port,
738 737 irp->irp_rp, 0, ELS_OP_RLS,
739 738 0, fct_rls_cb);
740 739 if (!cmd)
741 740 return (ENOMEM);
742 741 iport->iport_rls_cb_data.fct_link_status = link_status;
743 742 CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data;
744 743 fct_post_to_solcmd_queue(iport->iport_port, cmd);
745 744 sema_p(&iport->iport_rls_sema);
746 745 if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS)
747 746 ret = EIO;
748 747 return (ret);
749 748 }
750 749
751 750 static int
752 751 fct_forcelip(uint8_t *port_wwn, uint32_t *fctio_errno)
753 752 {
754 753 fct_status_t rval;
755 754 fct_i_local_port_t *iport;
756 755
757 756 mutex_enter(&fct_global_mutex);
758 757 iport = fct_get_iport_per_wwn(port_wwn);
759 758 mutex_exit(&fct_global_mutex);
760 759 if (iport == NULL) {
761 760 return (-1);
762 761 }
763 762
764 763 iport->iport_port->port_ctl(iport->iport_port,
765 764 FCT_CMD_FORCE_LIP, &rval);
766 765 if (rval != FCT_SUCCESS) {
767 766 *fctio_errno = FCTIO_FAILURE;
768 767 } else {
769 768 *fctio_errno = 0;
770 769 }
771 770
772 771 return (0);
773 772 }
774 773
775 774 static int
776 775 fct_fctiocmd(intptr_t data, int mode)
777 776 {
778 777 int ret = 0;
779 778 void *ibuf = NULL;
780 779 void *obuf = NULL;
781 780 void *abuf = NULL;
782 781 fctio_t *fctio;
783 782 uint32_t attr_length;
784 783
785 784 ret = fct_copyin_iocdata(data, mode, &fctio, &ibuf, &abuf, &obuf);
786 785 if (ret) {
787 786 return (ret);
788 787 }
789 788
790 789 switch (fctio->fctio_cmd) {
791 790 case FCTIO_ADAPTER_LIST: {
792 791 fc_tgt_hba_list_t *list = (fc_tgt_hba_list_t *)obuf;
793 792 int count;
794 793
795 794 if (fctio->fctio_olen < sizeof (fc_tgt_hba_list_t)) {
796 795 ret = EINVAL;
797 796 break;
798 797 }
799 798 list->numPorts = (fctio->fctio_olen -
800 799 sizeof (fc_tgt_hba_list_t))/8 + 1;
801 800
802 801 list->version = FCT_HBA_LIST_VERSION;
803 802 count = fct_get_port_list((char *)list->port_wwn,
804 803 list->numPorts);
805 804 if (count < 0) {
806 805 ret = ENXIO;
807 806 break;
808 807 }
809 808 if (count > list->numPorts) {
810 809 fctio->fctio_errno = FCTIO_MOREDATA;
811 810 ret = ENOSPC;
812 811 }
813 812 list->numPorts = count;
814 813 break;
815 814 }
816 815 case FCTIO_GET_ADAPTER_ATTRIBUTES: {
817 816 fc_tgt_hba_adapter_attributes_t *hba_attr;
818 817 uint8_t *port_wwn = (uint8_t *)ibuf;
819 818
820 819 attr_length = sizeof (fc_tgt_hba_adapter_attributes_t);
821 820 if (fctio->fctio_olen < attr_length ||
822 821 fctio->fctio_xfer != FCTIO_XFER_READ) {
823 822 ret = EINVAL;
824 823 break;
825 824 }
826 825 hba_attr = (fc_tgt_hba_adapter_attributes_t *)obuf;
827 826
828 827 mutex_enter(&fct_global_mutex);
829 828 ret = fct_get_adapter_attr(port_wwn, hba_attr,
830 829 &fctio->fctio_errno);
831 830 mutex_exit(&fct_global_mutex);
832 831
833 832 break;
834 833 }
835 834 case FCTIO_GET_ADAPTER_PORT_ATTRIBUTES: {
836 835 fc_tgt_hba_port_attributes_t *port_attr;
837 836
838 837 uint8_t *port_wwn = (uint8_t *)ibuf;
839 838
840 839 attr_length = sizeof (fc_tgt_hba_port_attributes_t);
841 840 if (fctio->fctio_olen < attr_length ||
842 841 fctio->fctio_xfer != FCTIO_XFER_READ) {
843 842 ret = EINVAL;
844 843 break;
845 844 }
846 845 port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
847 846
848 847 mutex_enter(&fct_global_mutex);
849 848 ret = fct_get_adapter_port_attr(NULL, port_wwn, port_attr,
850 849 &fctio->fctio_errno);
851 850 mutex_exit(&fct_global_mutex);
852 851
853 852 break;
854 853 }
855 854 case FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
856 855 uint8_t *port_wwn = (uint8_t *)ibuf;
857 856 uint32_t *port_index = (uint32_t *)abuf;
858 857 fc_tgt_hba_port_attributes_t *port_attr;
859 858
860 859 attr_length = sizeof (fc_tgt_hba_port_attributes_t);
861 860 if (fctio->fctio_olen < attr_length ||
862 861 fctio->fctio_xfer != FCTIO_XFER_READ) {
863 862 ret = EINVAL;
864 863 break;
865 864 }
866 865 port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
867 866
868 867 mutex_enter(&fct_global_mutex);
869 868 ret = fct_get_discovered_port_attr(NULL, port_wwn,
870 869 *port_index, port_attr, &fctio->fctio_errno);
871 870 mutex_exit(&fct_global_mutex);
872 871
873 872 break;
874 873 }
875 874 case FCTIO_GET_PORT_ATTRIBUTES: {
876 875 uint8_t *port_wwn = (uint8_t *)ibuf;
877 876 fc_tgt_hba_port_attributes_t *port_attr;
878 877
879 878 attr_length = sizeof (fc_tgt_hba_port_attributes_t);
880 879 if (fctio->fctio_olen < attr_length ||
881 880 fctio->fctio_xfer != FCTIO_XFER_READ) {
882 881 ret = EINVAL;
883 882 break;
884 883 }
885 884
886 885 port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
887 886
888 887 mutex_enter(&fct_global_mutex);
889 888 ret = fct_get_port_attr(port_wwn, port_attr,
890 889 &fctio->fctio_errno);
891 890 mutex_exit(&fct_global_mutex);
892 891
893 892 break;
894 893 }
895 894 case FCTIO_GET_ADAPTER_PORT_STATS: {
896 895 uint8_t *port_wwn = (uint8_t *)ibuf;
897 896 fc_tgt_hba_adapter_port_stats_t *port_stats =
898 897 (fc_tgt_hba_adapter_port_stats_t *)obuf;
899 898 mutex_enter(&fct_global_mutex);
900 899 ret = fct_get_port_stats(port_wwn, port_stats,
901 900 &fctio->fctio_errno);
902 901 mutex_exit(&fct_global_mutex);
903 902 break;
904 903 }
905 904 case FCTIO_GET_LINK_STATUS: {
906 905 uint8_t *port_wwn = (uint8_t *)ibuf;
907 906 fct_port_link_status_t *link_status =
908 907 (fct_port_link_status_t *)obuf;
909 908 uint64_t *dest_id = abuf;
910 909
911 910 mutex_enter(&fct_global_mutex);
912 911 ret = fct_get_link_status(port_wwn, dest_id, link_status,
913 912 &fctio->fctio_errno);
914 913 mutex_exit(&fct_global_mutex);
915 914 break;
916 915 }
917 916
918 917 case FCTIO_FORCE_LIP:
919 918 ret = fct_forcelip((uint8_t *)ibuf, &fctio->fctio_errno);
920 919 break;
921 920
922 921 default:
923 922 break;
924 923 }
925 924 if (ret == 0) {
926 925 ret = fct_copyout_iocdata(data, mode, fctio, obuf);
927 926 } else if (fctio->fctio_errno) {
928 927 (void) fct_copyout_iocdata(data, mode, fctio, obuf);
929 928 }
930 929
931 930 if (obuf) {
932 931 kmem_free(obuf, fctio->fctio_olen);
933 932 obuf = NULL;
934 933 }
935 934 if (abuf) {
936 935 kmem_free(abuf, fctio->fctio_alen);
937 936 abuf = NULL;
938 937 }
939 938
940 939 if (ibuf) {
941 940 kmem_free(ibuf, fctio->fctio_ilen);
942 941 ibuf = NULL;
943 942 }
944 943 kmem_free(fctio, sizeof (fctio_t));
945 944 return (ret);
946 945 }
947 946
948 947 typedef struct {
949 948 void *bp; /* back pointer from internal struct to main struct */
950 949 int alloc_size;
951 950 fct_struct_id_t struct_id;
952 951 } __ifct_t;
953 952
954 953 typedef struct {
955 954 __ifct_t *fp; /* Framework private */
956 955 void *cp; /* Caller private */
957 956 void *ss; /* struct specific */
958 957 } __fct_t;
959 958
960 959 static struct {
961 960 int shared;
962 961 int fw_private;
963 962 int struct_specific;
964 963 } fct_sizes[] = { { 0, 0, 0 },
965 964 { GET_STRUCT_SIZE(fct_local_port_t),
966 965 GET_STRUCT_SIZE(fct_i_local_port_t), 0 },
967 966 { GET_STRUCT_SIZE(fct_remote_port_t),
968 967 GET_STRUCT_SIZE(fct_i_remote_port_t), 0 },
969 968 { GET_STRUCT_SIZE(fct_cmd_t),
970 969 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
971 970 { GET_STRUCT_SIZE(fct_cmd_t),
972 971 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
973 972 { GET_STRUCT_SIZE(fct_cmd_t),
974 973 GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_sol_ct_t) },
975 974 { GET_STRUCT_SIZE(fct_cmd_t), GET_STRUCT_SIZE(fct_i_cmd_t),
976 975 GET_STRUCT_SIZE(fct_rcvd_abts_t) },
977 976 { GET_STRUCT_SIZE(fct_cmd_t), /* FCT_STRUCT_CMD_FCP_XCHG */
978 977 GET_STRUCT_SIZE(fct_i_cmd_t), 0 },
979 978 { GET_STRUCT_SIZE(fct_dbuf_store_t),
980 979 GET_STRUCT_SIZE(__ifct_t), 0 }
981 980 };
982 981
983 982 void *
984 983 fct_alloc(fct_struct_id_t struct_id, int additional_size, int flags)
985 984 {
986 985 int fct_size;
987 986 int kmem_flag;
988 987 __fct_t *sh;
989 988
990 989 if ((struct_id == 0) || (struct_id >= FCT_MAX_STRUCT_IDS))
991 990 return (NULL);
992 991
993 992 if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
994 993 kmem_flag = KM_NOSLEEP;
995 994 } else {
996 995 kmem_flag = KM_SLEEP;
997 996 }
998 997
999 998 additional_size = (additional_size + 7) & (~7);
1000 999 fct_size = fct_sizes[struct_id].shared +
1001 1000 fct_sizes[struct_id].fw_private +
1002 1001 fct_sizes[struct_id].struct_specific + additional_size;
1003 1002
1004 1003 if (struct_id == FCT_STRUCT_LOCAL_PORT) {
1005 1004 stmf_local_port_t *lport;
1006 1005
1007 1006 lport = (stmf_local_port_t *)stmf_alloc(
1008 1007 STMF_STRUCT_STMF_LOCAL_PORT, fct_size, flags);
1009 1008 if (lport) {
1010 1009 sh = (__fct_t *)lport->lport_port_private;
1011 1010 sh->ss = lport;
1012 1011 } else {
1013 1012 return (NULL);
1014 1013 }
1015 1014 } else if (struct_id == FCT_STRUCT_DBUF_STORE) {
1016 1015 stmf_dbuf_store_t *ds;
1017 1016
1018 1017 ds = (stmf_dbuf_store_t *)stmf_alloc(STMF_STRUCT_DBUF_STORE,
1019 1018 fct_size, flags);
1020 1019 if (ds) {
1021 1020 sh = (__fct_t *)ds->ds_port_private;
1022 1021 sh->ss = ds;
1023 1022 } else {
1024 1023 return (NULL);
1025 1024 }
1026 1025 } else {
1027 1026 sh = (__fct_t *)kmem_zalloc(fct_size, kmem_flag);
1028 1027 }
1029 1028
1030 1029 if (sh == NULL)
1031 1030 return (NULL);
1032 1031
1033 1032 sh->fp = (__ifct_t *)GET_BYTE_OFFSET(sh, fct_sizes[struct_id].shared);
1034 1033 sh->cp = GET_BYTE_OFFSET(sh->fp, fct_sizes[struct_id].fw_private);
1035 1034 if (fct_sizes[struct_id].struct_specific)
1036 1035 sh->ss = GET_BYTE_OFFSET(sh->cp, additional_size);
1037 1036
1038 1037 sh->fp->bp = sh;
1039 1038 sh->fp->alloc_size = fct_size;
1040 1039 sh->fp->struct_id = struct_id;
1041 1040
1042 1041 if (struct_id == FCT_STRUCT_CMD_FCP_XCHG) {
1043 1042 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_FCP_XCHG;
1044 1043 } else if (struct_id == FCT_STRUCT_CMD_RCVD_ELS) {
1045 1044 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ELS;
1046 1045 } else if (struct_id == FCT_STRUCT_CMD_SOL_ELS) {
1047 1046 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_ELS;
1048 1047 } else if (struct_id == FCT_STRUCT_CMD_RCVD_ABTS) {
1049 1048 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ABTS;
1050 1049 } else if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
1051 1050 ((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_CT;
1052 1051 }
1053 1052
1054 1053 return (sh);
1055 1054 }
1056 1055
1057 1056 void
1058 1057 fct_free(void *ptr)
1059 1058 {
1060 1059 __fct_t *sh = (__fct_t *)ptr;
1061 1060 fct_struct_id_t struct_id = sh->fp->struct_id;
1062 1061
1063 1062 if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
1064 1063 fct_sol_ct_t *ct = (fct_sol_ct_t *)
1065 1064 ((fct_cmd_t *)ptr)->cmd_specific;
1066 1065
1067 1066 if (ct->ct_req_alloc_size) {
1068 1067 kmem_free(ct->ct_req_payload, ct->ct_req_alloc_size);
1069 1068 }
1070 1069 if (ct->ct_resp_alloc_size) {
1071 1070 kmem_free(ct->ct_resp_payload, ct->ct_resp_alloc_size);
1072 1071 }
1073 1072 } else if ((struct_id == FCT_STRUCT_CMD_RCVD_ELS) ||
1074 1073 (struct_id == FCT_STRUCT_CMD_SOL_ELS)) {
1075 1074 fct_els_t *els = (fct_els_t *)
1076 1075 ((fct_cmd_t *)ptr)->cmd_specific;
1077 1076 if (els->els_req_alloc_size)
1078 1077 kmem_free(els->els_req_payload,
1079 1078 els->els_req_alloc_size);
1080 1079 if (els->els_resp_alloc_size)
1081 1080 kmem_free(els->els_resp_payload,
1082 1081 els->els_resp_alloc_size);
1083 1082 }
1084 1083
1085 1084 if (struct_id == FCT_STRUCT_LOCAL_PORT) {
1086 1085 stmf_free(((fct_local_port_t *)ptr)->port_lport);
1087 1086 } else if (struct_id == FCT_STRUCT_DBUF_STORE) {
1088 1087 stmf_free(((fct_dbuf_store_t *)ptr)->fds_ds);
1089 1088 } else {
1090 1089 kmem_free(ptr, sh->fp->alloc_size);
1091 1090 }
1092 1091 }
1093 1092
1094 1093 stmf_data_buf_t *
1095 1094 fct_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
1096 1095 uint32_t flags)
1097 1096 {
1098 1097 fct_local_port_t *port = (fct_local_port_t *)
1099 1098 task->task_lport->lport_port_private;
1100 1099
1101 1100 return (port->port_fds->fds_alloc_data_buf(port, size,
1102 1101 pminsize, flags));
1103 1102 }
1104 1103
1105 1104 stmf_status_t
1106 1105 fct_setup_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t flags)
1107 1106 {
1108 1107 fct_local_port_t *port = (fct_local_port_t *)
1109 1108 task->task_lport->lport_port_private;
1110 1109
1111 1110 ASSERT(port->port_fds->fds_setup_dbuf != NULL);
1112 1111 if (port->port_fds->fds_setup_dbuf == NULL)
1113 1112 return (STMF_FAILURE);
1114 1113
1115 1114 return (port->port_fds->fds_setup_dbuf(port, dbuf, flags));
1116 1115 }
1117 1116
1118 1117 void
1119 1118 fct_teardown_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
1120 1119 {
1121 1120 fct_dbuf_store_t *fds = ds->ds_port_private;
1122 1121
1123 1122 fds->fds_teardown_dbuf(fds, dbuf);
1124 1123 }
1125 1124
1126 1125 void
1127 1126 fct_free_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
1128 1127 {
1129 1128 fct_dbuf_store_t *fds;
1130 1129
1131 1130 fds = (fct_dbuf_store_t *)ds->ds_port_private;
1132 1131
1133 1132 fds->fds_free_data_buf(fds, dbuf);
1134 1133 }
1135 1134
1136 1135 static uint32_t taskq_cntr = 0;
1137 1136
1138 1137 fct_status_t
1139 1138 fct_register_local_port(fct_local_port_t *port)
1140 1139 {
1141 1140 fct_i_local_port_t *iport;
1142 1141 stmf_local_port_t *lport;
1143 1142 fct_cmd_slot_t *slot;
1144 1143 int i;
1145 1144 char taskq_name[FCT_TASKQ_NAME_LEN];
1146 1145
1147 1146 iport = (fct_i_local_port_t *)port->port_fct_private;
1148 1147 if (port->port_fca_version != FCT_FCA_MODREV_1) {
1149 1148 cmn_err(CE_WARN,
1150 1149 "fct: %s driver version mismatch",
1151 1150 port->port_default_alias);
1152 1151 return (FCT_FAILURE);
1153 1152 }
1154 1153 if (port->port_default_alias) {
1155 1154 int l = strlen(port->port_default_alias);
1156 1155
1157 1156 if (l < 16) {
1158 1157 iport->iport_alias = iport->iport_alias_mem;
1159 1158 } else {
1160 1159 iport->iport_alias =
1161 1160 (char *)kmem_zalloc(l+1, KM_SLEEP);
1162 1161 }
1163 1162 (void) strcpy(iport->iport_alias, port->port_default_alias);
1164 1163 } else {
1165 1164 iport->iport_alias = NULL;
1166 1165 }
1167 1166 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id,
1168 1167 port->port_pwwn, PROTOCOL_FIBRE_CHANNEL);
1169 1168 (void) snprintf(taskq_name, sizeof (taskq_name), "stmf_fct_taskq_%d",
1170 1169 atomic_inc_32_nv(&taskq_cntr));
1171 1170 if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1172 1171 taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1173 1172 return (FCT_FAILURE);
1174 1173 }
1175 1174 mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1176 1175 cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1177 1176 rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1178 1177 sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1179 1178
1180 1179 /* Remote port mgmt */
1181 1180 iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1182 1181 port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1183 1182 iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1184 1183 sizeof (fct_i_remote_port_t *), KM_SLEEP);
1185 1184
1186 1185 /* fct_cmds for SCSI traffic */
1187 1186 iport->iport_total_alloced_ncmds = 0;
1188 1187 iport->iport_cached_ncmds = 0;
1189 1188 port->port_fca_fcp_cmd_size =
1190 1189 (port->port_fca_fcp_cmd_size + 7) & ~7;
1191 1190 iport->iport_cached_cmdlist = NULL;
1192 1191 mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL);
1193 1192
1194 1193 /* Initialize cmd slots */
1195 1194 iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc(
1196 1195 port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP);
1197 1196 iport->iport_next_free_slot = 0;
1198 1197 for (i = 0; i < port->port_max_xchges; ) {
1199 1198 slot = &iport->iport_cmd_slots[i];
1200 1199 slot->slot_no = (uint16_t)i;
1201 1200 slot->slot_next = (uint16_t)(++i);
1202 1201 }
1203 1202 slot->slot_next = FCT_SLOT_EOL;
1204 1203 iport->iport_nslots_free = port->port_max_xchges;
1205 1204
1206 1205 iport->iport_task_green_limit =
1207 1206 (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100;
1208 1207 iport->iport_task_yellow_limit =
1209 1208 (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100;
1210 1209 iport->iport_task_red_limit =
1211 1210 (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100;
1212 1211
1213 1212 /* Start worker thread */
1214 1213 atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
1215 1214 (void) ddi_taskq_dispatch(iport->iport_worker_taskq,
1216 1215 fct_port_worker, port, DDI_SLEEP);
1217 1216 /* Wait for taskq to start */
1218 1217 while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
1219 1218 delay(1);
1220 1219 }
1221 1220
1222 1221 lport = port->port_lport;
1223 1222 lport->lport_id = (scsi_devid_desc_t *)iport->iport_id;
1224 1223 lport->lport_alias = iport->iport_alias;
1225 1224 lport->lport_pp = port->port_pp;
1226 1225 port->port_fds->fds_ds->ds_alloc_data_buf = fct_alloc_dbuf;
1227 1226 port->port_fds->fds_ds->ds_free_data_buf = fct_free_dbuf;
1228 1227 port->port_fds->fds_ds->ds_setup_dbuf = fct_setup_dbuf;
1229 1228 port->port_fds->fds_ds->ds_teardown_dbuf = fct_teardown_dbuf;
1230 1229 lport->lport_ds = port->port_fds->fds_ds;
1231 1230 lport->lport_xfer_data = fct_xfer_scsi_data;
1232 1231 lport->lport_send_status = fct_send_scsi_status;
1233 1232 lport->lport_task_free = fct_scsi_task_free;
1234 1233 lport->lport_abort = fct_scsi_abort;
1235 1234 lport->lport_ctl = fct_ctl;
1236 1235 lport->lport_info = fct_info;
1237 1236 lport->lport_event_handler = fct_event_handler;
1238 1237 /* set up as alua participating port */
1239 1238 stmf_set_port_alua(lport);
1240 1239 if (stmf_register_local_port(port->port_lport) != FCT_SUCCESS) {
1241 1240 goto fct_regport_fail1;
1242 1241 }
1243 1242 (void) stmf_lport_add_event(lport, LPORT_EVENT_INITIAL_LUN_MAPPED);
1244 1243
1245 1244 mutex_enter(&fct_global_mutex);
1246 1245 iport->iport_next = fct_iport_list;
1247 1246 iport->iport_prev = NULL;
1248 1247 if (iport->iport_next)
1249 1248 iport->iport_next->iport_prev = iport;
1250 1249 fct_iport_list = iport;
1251 1250 mutex_exit(&fct_global_mutex);
1252 1251
1253 1252 fct_init_kstats(iport);
1254 1253
1255 1254 fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH);
1256 1255
1257 1256 return (FCT_SUCCESS);
1258 1257
1259 1258 fct_regport_fail1:;
1260 1259 /* Stop the taskq 1st */
1261 1260 if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1262 1261 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1263 1262 cv_broadcast(&iport->iport_worker_cv);
1264 1263 while (iport->iport_flags & IPORT_WORKER_RUNNING) {
1265 1264 delay(1);
1266 1265 }
1267 1266 }
1268 1267 ddi_taskq_destroy(iport->iport_worker_taskq);
1269 1268 if (iport->iport_rp_tb) {
1270 1269 kmem_free(iport->iport_rp_tb, rportid_table_size *
1271 1270 sizeof (fct_i_remote_port_t *));
1272 1271 }
1273 1272 return (FCT_FAILURE);
1274 1273 }
1275 1274
1276 1275 fct_status_t
1277 1276 fct_deregister_local_port(fct_local_port_t *port)
1278 1277 {
1279 1278 fct_i_local_port_t *iport;
1280 1279 fct_i_cmd_t *icmd, *next_icmd;
1281 1280 int ndx;
1282 1281
1283 1282 iport = (fct_i_local_port_t *)port->port_fct_private;
1284 1283
1285 1284 if ((iport->iport_state != FCT_STATE_OFFLINE) ||
1286 1285 iport->iport_state_not_acked) {
1287 1286 return (FCT_FAILURE);
1288 1287 }
1289 1288
1290 1289 /* Stop the taskq 1st */
1291 1290 if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1292 1291 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1293 1292 cv_broadcast(&iport->iport_worker_cv);
1294 1293 for (ndx = 0; ndx < 100; ndx++) {
1295 1294 if ((iport->iport_flags & IPORT_WORKER_RUNNING)
1296 1295 == 0) {
1297 1296 break;
1298 1297 }
1299 1298 delay(drv_usectohz(10000));
1300 1299 }
1301 1300 if (ndx == 100) {
1302 1301 atomic_and_32(&iport->iport_flags,
1303 1302 ~IPORT_TERMINATE_WORKER);
1304 1303 return (FCT_WORKER_STUCK);
1305 1304 }
1306 1305 }
1307 1306
1308 1307 if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) {
1309 1308 goto fct_deregport_fail1;
1310 1309 }
1311 1310
1312 1311 mutex_enter(&fct_global_mutex);
1313 1312 if (iport->iport_next)
1314 1313 iport->iport_next->iport_prev = iport->iport_prev;
1315 1314 if (iport->iport_prev)
1316 1315 iport->iport_prev->iport_next = iport->iport_next;
1317 1316 else
1318 1317 fct_iport_list = iport->iport_next;
1319 1318 mutex_exit(&fct_global_mutex);
1320 1319 /*
1321 1320 * At this time, there should be no outstanding and pending
1322 1321 * I/Os, so we can just release resources.
1323 1322 */
1324 1323 ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds);
1325 1324 for (icmd = iport->iport_cached_cmdlist; icmd; icmd = next_icmd) {
1326 1325 next_icmd = icmd->icmd_next;
1327 1326 fct_free(icmd->icmd_cmd);
1328 1327 }
1329 1328 mutex_destroy(&iport->iport_cached_cmd_lock);
1330 1329 kmem_free(iport->iport_cmd_slots, port->port_max_xchges *
1331 1330 sizeof (fct_cmd_slot_t));
1332 1331 kmem_free(iport->iport_rp_slots, port->port_max_logins *
1333 1332 sizeof (fct_i_remote_port_t *));
1334 1333 rw_destroy(&iport->iport_lock);
1335 1334 cv_destroy(&iport->iport_worker_cv);
1336 1335 sema_destroy(&iport->iport_rls_sema);
1337 1336 mutex_destroy(&iport->iport_worker_lock);
1338 1337 ddi_taskq_destroy(iport->iport_worker_taskq);
1339 1338 if (iport->iport_rp_tb) {
1340 1339 kmem_free(iport->iport_rp_tb, rportid_table_size *
1341 1340 sizeof (fct_i_remote_port_t *));
1342 1341 }
1343 1342
1344 1343 if (iport->iport_kstat_portstat) {
1345 1344 kstat_delete(iport->iport_kstat_portstat);
1346 1345 }
1347 1346
1348 1347 fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH);
1349 1348 return (FCT_SUCCESS);
1350 1349
1351 1350 fct_deregport_fail1:;
1352 1351 /* Restart the worker */
1353 1352 atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
1354 1353 (void) ddi_taskq_dispatch(iport->iport_worker_taskq,
1355 1354 fct_port_worker, port, DDI_SLEEP);
1356 1355 /* Wait for taskq to start */
1357 1356 while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
1358 1357 delay(1);
1359 1358 }
1360 1359 return (FCT_FAILURE);
1361 1360 }
1362 1361
1363 1362 /* ARGSUSED */
1364 1363 void
1365 1364 fct_handle_event(fct_local_port_t *port, int event_id, uint32_t event_flags,
1366 1365 caddr_t arg)
1367 1366 {
1368 1367 char info[FCT_INFO_LEN];
1369 1368 fct_i_event_t *e;
1370 1369 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1371 1370 port->port_fct_private;
1372 1371
1373 1372 e = kmem_zalloc(sizeof (fct_i_event_t), KM_NOSLEEP);
1374 1373
1375 1374 if (e == NULL) {
1376 1375 /*
1377 1376 * XXX Throw HBA fatal error event
1378 1377 */
1379 1378 (void) snprintf(info, sizeof (info),
1380 1379 "fct_handle_event: iport-%p, allocation "
1381 1380 "of fct_i_event failed", (void *)iport);
1382 1381 (void) fct_port_shutdown(iport->iport_port,
1383 1382 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1384 1383 return;
1385 1384 }
1386 1385 /* Just queue the event */
1387 1386 e->event_type = event_id;
1388 1387 mutex_enter(&iport->iport_worker_lock);
1389 1388 if (iport->iport_event_head == NULL) {
1390 1389 iport->iport_event_head = iport->iport_event_tail = e;
1391 1390 } else {
1392 1391 iport->iport_event_tail->event_next = e;
1393 1392 iport->iport_event_tail = e;
1394 1393 }
1395 1394 if (IS_WORKER_SLEEPING(iport))
1396 1395 cv_signal(&iport->iport_worker_cv);
1397 1396 mutex_exit(&iport->iport_worker_lock);
1398 1397 }
1399 1398
1400 1399 /*
1401 1400 * Called with iport_lock held as reader.
1402 1401 */
1403 1402 fct_i_remote_port_t *
1404 1403 fct_portid_to_portptr(fct_i_local_port_t *iport, uint32_t portid)
1405 1404 {
1406 1405 fct_i_remote_port_t *irp;
1407 1406
1408 1407 irp = iport->iport_rp_tb[FCT_PORTID_HASH_FUNC(portid)];
1409 1408 for (; irp != NULL; irp = irp->irp_next) {
1410 1409 if (irp->irp_portid == portid)
1411 1410 return (irp);
1412 1411 }
1413 1412
1414 1413 return (NULL);
1415 1414
1416 1415 }
1417 1416
1418 1417 /*
1419 1418 * Called with irp_lock held as writer.
1420 1419 */
1421 1420 void
1422 1421 fct_queue_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1423 1422 {
1424 1423 int hash_key =
1425 1424 FCT_PORTID_HASH_FUNC(irp->irp_portid);
1426 1425
1427 1426 irp->irp_next = iport->iport_rp_tb[hash_key];
1428 1427 iport->iport_rp_tb[hash_key] = irp;
1429 1428 iport->iport_nrps++;
1430 1429 }
1431 1430
1432 1431 /*
1433 1432 * Called with irp_lock and iport_lock held as writer.
1434 1433 */
1435 1434 void
1436 1435 fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1437 1436 {
1438 1437 fct_i_remote_port_t *irp_next = NULL;
1439 1438 fct_i_remote_port_t *irp_last = NULL;
1440 1439 int hash_key =
1441 1440 FCT_PORTID_HASH_FUNC(irp->irp_portid);
1442 1441
1443 1442 irp_next = iport->iport_rp_tb[hash_key];
1444 1443 irp_last = NULL;
1445 1444 while (irp_next != NULL) {
1446 1445 if (irp == irp_next) {
1447 1446 if (irp->irp_flags & IRP_PLOGI_DONE) {
1448 1447 atomic_dec_32(&iport->iport_nrps_login);
1449 1448 }
1450 1449 atomic_and_32(&irp->irp_flags,
1451 1450 ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1452 1451 break;
1453 1452 }
1454 1453 irp_last = irp_next;
1455 1454 irp_next = irp_next->irp_next;
1456 1455 }
1457 1456
1458 1457 if (irp_next) {
1459 1458 if (irp_last == NULL) {
1460 1459 iport->iport_rp_tb[hash_key] =
1461 1460 irp->irp_next;
1462 1461 } else {
1463 1462 irp_last->irp_next = irp->irp_next;
1464 1463 }
1465 1464 irp->irp_next = NULL;
1466 1465 iport->iport_nrps--;
1467 1466 }
1468 1467 }
1469 1468
1470 1469 int
1471 1470 fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit)
1472 1471 {
1473 1472 int logging_out = 0;
1474 1473
1475 1474 rw_enter(&irp->irp_lock, RW_WRITER);
1476 1475 if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1477 1476 logging_out = 0;
1478 1477 goto ilo_done;
1479 1478 }
1480 1479 if ((irp->irp_els_list == NULL) && (irp->irp_deregister_timer)) {
1481 1480 if (force_implicit && irp->irp_nonfcp_xchg_count) {
1482 1481 logging_out = 0;
1483 1482 } else {
1484 1483 logging_out = 1;
1485 1484 }
1486 1485 goto ilo_done;
1487 1486 }
1488 1487 if (irp->irp_els_list) {
1489 1488 fct_i_cmd_t *icmd;
1490 1489 /* Last session affecting ELS should be a LOGO */
1491 1490 for (icmd = irp->irp_els_list; icmd; icmd = icmd->icmd_next) {
1492 1491 uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0];
1493 1492 if (op == ELS_OP_LOGO) {
1494 1493 if (force_implicit) {
1495 1494 if (icmd->icmd_flags & ICMD_IMPLICIT)
1496 1495 logging_out = 1;
1497 1496 else
1498 1497 logging_out = 0;
1499 1498 } else {
1500 1499 logging_out = 1;
1501 1500 }
1502 1501 } else if ((op == ELS_OP_PLOGI) ||
1503 1502 (op == ELS_OP_PRLI) ||
1504 1503 (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
1505 1504 logging_out = 0;
1506 1505 }
1507 1506 }
1508 1507 }
1509 1508 ilo_done:;
1510 1509 rw_exit(&irp->irp_lock);
1511 1510
1512 1511 return (logging_out);
1513 1512 }
1514 1513
1515 1514 /*
1516 1515 * The force_implicit flag enforces the implicit semantics which may be
1517 1516 * needed if a received logout got stuck e.g. a response to a received
1518 1517 * LOGO never came back from the FCA.
1519 1518 */
1520 1519 int
1521 1520 fct_implicitly_logo_all(fct_i_local_port_t *iport, int force_implicit)
1522 1521 {
1523 1522 fct_i_remote_port_t *irp = NULL;
1524 1523 fct_cmd_t *cmd = NULL;
1525 1524 int i = 0;
1526 1525 int nports = 0;
1527 1526
1528 1527 if (!iport->iport_nrps) {
1529 1528 return (nports);
1530 1529 }
1531 1530
1532 1531 rw_enter(&iport->iport_lock, RW_WRITER);
1533 1532 for (i = 0; i < rportid_table_size; i++) {
1534 1533 irp = iport->iport_rp_tb[i];
1535 1534 while (irp) {
1536 1535 if ((!(irp->irp_flags & IRP_PLOGI_DONE)) &&
1537 1536 (fct_is_irp_logging_out(irp, force_implicit))) {
1538 1537 irp = irp->irp_next;
1539 1538 continue;
1540 1539 }
1541 1540
1542 1541 cmd = fct_create_solels(iport->iport_port, irp->irp_rp,
1543 1542 1, ELS_OP_LOGO, 0, fct_logo_cb);
1544 1543 if (cmd == NULL) {
1545 1544 stmf_trace(iport->iport_alias,
1546 1545 "fct_implictly_logo_all: cmd null");
1547 1546 rw_exit(&iport->iport_lock);
1548 1547
1549 1548 return (nports);
1550 1549 }
1551 1550
1552 1551 fct_post_implicit_logo(cmd);
1553 1552 nports++;
1554 1553 irp = irp->irp_next;
1555 1554 }
1556 1555 }
1557 1556 rw_exit(&iport->iport_lock);
1558 1557
1559 1558 return (nports);
1560 1559 }
1561 1560
1562 1561 void
1563 1562 fct_rehash(fct_i_local_port_t *iport)
1564 1563 {
1565 1564 fct_i_remote_port_t **iport_rp_tb_tmp;
1566 1565 fct_i_remote_port_t **iport_rp_tb_new;
1567 1566 fct_i_remote_port_t *irp;
1568 1567 fct_i_remote_port_t *irp_next;
1569 1568 int i;
1570 1569
1571 1570 iport_rp_tb_new = kmem_zalloc(rportid_table_size *
1572 1571 sizeof (fct_i_remote_port_t *), KM_SLEEP);
1573 1572 rw_enter(&iport->iport_lock, RW_WRITER);
1574 1573 /* reconstruct the hash table */
1575 1574 iport_rp_tb_tmp = iport->iport_rp_tb;
1576 1575 iport->iport_rp_tb = iport_rp_tb_new;
1577 1576 iport->iport_nrps = 0;
1578 1577 for (i = 0; i < rportid_table_size; i++) {
1579 1578 irp = iport_rp_tb_tmp[i];
1580 1579 while (irp) {
1581 1580 irp_next = irp->irp_next;
1582 1581 fct_queue_rp(iport, irp);
1583 1582 irp = irp_next;
1584 1583 }
1585 1584 }
1586 1585 rw_exit(&iport->iport_lock);
1587 1586 kmem_free(iport_rp_tb_tmp, rportid_table_size *
1588 1587 sizeof (fct_i_remote_port_t *));
1589 1588
1590 1589 }
1591 1590
1592 1591 uint8_t
1593 1592 fct_local_port_cleanup_done(fct_i_local_port_t *iport)
1594 1593 {
1595 1594 fct_i_remote_port_t *irp;
1596 1595 int i;
1597 1596
1598 1597 if (iport->iport_nrps_login)
1599 1598 return (0);
1600 1599 /* loop all rps to check if the cmd have already been drained */
1601 1600 for (i = 0; i < rportid_table_size; i++) {
1602 1601 irp = iport->iport_rp_tb[i];
1603 1602 while (irp) {
1604 1603 if (irp->irp_fcp_xchg_count ||
1605 1604 irp->irp_nonfcp_xchg_count)
1606 1605 return (0);
1607 1606 irp = irp->irp_next;
1608 1607 }
1609 1608 }
1610 1609 return (1);
1611 1610 }
1612 1611
1613 1612 fct_cmd_t *
1614 1613 fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle,
1615 1614 uint32_t rportid, uint8_t *lun, uint16_t cdb_length, uint16_t task_ext)
1616 1615 {
1617 1616 fct_cmd_t *cmd;
1618 1617 fct_i_cmd_t *icmd;
1619 1618 fct_i_local_port_t *iport =
1620 1619 (fct_i_local_port_t *)port->port_fct_private;
1621 1620 fct_i_remote_port_t *irp;
1622 1621 scsi_task_t *task;
1623 1622 fct_remote_port_t *rp;
1624 1623 uint16_t cmd_slot;
1625 1624
1626 1625 rw_enter(&iport->iport_lock, RW_READER);
1627 1626 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
1628 1627 rw_exit(&iport->iport_lock);
1629 1628 stmf_trace(iport->iport_alias, "cmd alloc called while the port"
1630 1629 " was offline");
1631 1630 return (NULL);
1632 1631 }
1633 1632
1634 1633 if (rp_handle == FCT_HANDLE_NONE) {
1635 1634 irp = fct_portid_to_portptr(iport, rportid);
1636 1635 if (irp == NULL) {
1637 1636 rw_exit(&iport->iport_lock);
1638 1637 stmf_trace(iport->iport_alias, "cmd received from "
1639 1638 "non existent port %x", rportid);
1640 1639 return (NULL);
1641 1640 }
1642 1641 } else {
1643 1642 if ((rp_handle >= port->port_max_logins) ||
1644 1643 ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) {
1645 1644 rw_exit(&iport->iport_lock);
1646 1645 stmf_trace(iport->iport_alias, "cmd received from "
1647 1646 "invalid port handle %x", rp_handle);
1648 1647 return (NULL);
1649 1648 }
1650 1649 }
1651 1650 rp = irp->irp_rp;
1652 1651
1653 1652 rw_enter(&irp->irp_lock, RW_READER);
1654 1653 if ((irp->irp_flags & IRP_PRLI_DONE) == 0) {
1655 1654 rw_exit(&irp->irp_lock);
1656 1655 rw_exit(&iport->iport_lock);
1657 1656 stmf_trace(iport->iport_alias, "cmd alloc called while fcp "
1658 1657 "login was not done. portid=%x, rp=%p", rp->rp_id, rp);
1659 1658 return (NULL);
1660 1659 }
1661 1660
1662 1661 mutex_enter(&iport->iport_cached_cmd_lock);
1663 1662 if ((icmd = iport->iport_cached_cmdlist) != NULL) {
1664 1663 iport->iport_cached_cmdlist = icmd->icmd_next;
1665 1664 iport->iport_cached_ncmds--;
1666 1665 cmd = icmd->icmd_cmd;
1667 1666 } else {
1668 1667 icmd = NULL;
1669 1668 }
1670 1669 mutex_exit(&iport->iport_cached_cmd_lock);
1671 1670 if (icmd == NULL) {
1672 1671 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1673 1672 port->port_fca_fcp_cmd_size, 0);
1674 1673 if (cmd == NULL) {
1675 1674 rw_exit(&irp->irp_lock);
1676 1675 rw_exit(&iport->iport_lock);
1677 1676 stmf_trace(iport->iport_alias, "Ran out of "
1678 1677 "memory, port=%p", port);
1679 1678 return (NULL);
1680 1679 }
1681 1680
1682 1681 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1683 1682 icmd->icmd_next = NULL;
1684 1683 cmd->cmd_port = port;
1685 1684 atomic_inc_32(&iport->iport_total_alloced_ncmds);
1686 1685 }
1687 1686
1688 1687 /*
1689 1688 * The accuracy of iport_max_active_ncmds is not important
1690 1689 */
1691 1690 if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1692 1691 iport->iport_max_active_ncmds) {
1693 1692 iport->iport_max_active_ncmds =
1694 1693 iport->iport_total_alloced_ncmds -
1695 1694 iport->iport_cached_ncmds;
1696 1695 }
1697 1696
1698 1697 /* Lets get a slot */
1699 1698 cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1700 1699 if (cmd_slot == FCT_SLOT_EOL) {
1701 1700 rw_exit(&irp->irp_lock);
1702 1701 rw_exit(&iport->iport_lock);
1703 1702 stmf_trace(iport->iport_alias, "Ran out of xchg resources");
1704 1703 cmd->cmd_handle = 0;
1705 1704 fct_cmd_free(cmd);
1706 1705 return (NULL);
1707 1706 }
1708 1707 atomic_inc_16(&irp->irp_fcp_xchg_count);
1709 1708 cmd->cmd_rp = rp;
1710 1709 icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA;
1711 1710 rw_exit(&irp->irp_lock);
1712 1711 rw_exit(&iport->iport_lock);
1713 1712
1714 1713 icmd->icmd_start_time = ddi_get_lbolt();
1715 1714
1716 1715 cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session,
1717 1716 lun, cdb_length, task_ext);
1718 1717 if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) {
1719 1718 task->task_port_private = cmd;
1720 1719 return (cmd);
1721 1720 }
1722 1721
1723 1722 fct_cmd_free(cmd);
1724 1723
1725 1724 return (NULL);
1726 1725 }
1727 1726
1728 1727 void
1729 1728 fct_scsi_task_free(scsi_task_t *task)
1730 1729 {
1731 1730 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1732 1731
1733 1732 cmd->cmd_comp_status = task->task_completion_status;
1734 1733 fct_cmd_free(cmd);
1735 1734 }
1736 1735
1737 1736 void
1738 1737 fct_post_rcvd_cmd(fct_cmd_t *cmd, stmf_data_buf_t *dbuf)
1739 1738 {
1740 1739 fct_dbuf_store_t *fds;
1741 1740
1742 1741 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
1743 1742 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1744 1743 fct_i_local_port_t *iport =
1745 1744 (fct_i_local_port_t *)cmd->cmd_port->port_fct_private;
1746 1745 fct_i_remote_port_t *irp =
1747 1746 (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private;
1748 1747 scsi_task_t *task = (scsi_task_t *)cmd->cmd_specific;
1749 1748
1750 1749 uint16_t irp_task = irp->irp_fcp_xchg_count;
1751 1750 uint32_t load = iport->iport_total_alloced_ncmds -
1752 1751 iport->iport_cached_ncmds;
1753 1752
1754 1753 DTRACE_FC_4(scsi__command,
1755 1754 fct_cmd_t, cmd,
1756 1755 fct_i_local_port_t, iport,
1757 1756 scsi_task_t, task,
1758 1757 fct_i_remote_port_t, irp);
1759 1758
1760 1759 if (load >= iport->iport_task_green_limit) {
1761 1760 if ((load < iport->iport_task_yellow_limit &&
1762 1761 irp_task >= 4) ||
1763 1762 (load >= iport->iport_task_yellow_limit &&
1764 1763 load < iport->iport_task_red_limit &&
1765 1764 irp_task >= 1) ||
1766 1765 (load >= iport->iport_task_red_limit))
1767 1766 task->task_additional_flags |=
1768 1767 TASK_AF_PORT_LOAD_HIGH;
1769 1768 }
1770 1769 /*
1771 1770 * If the target driver accepts sglists, fill in task fields.
1772 1771 */
1773 1772 fds = cmd->cmd_port->port_fds;
1774 1773 if (fds->fds_setup_dbuf != NULL) {
1775 1774 task->task_additional_flags |= TASK_AF_ACCEPT_LU_DBUF;
1776 1775 task->task_copy_threshold = fds->fds_copy_threshold;
1777 1776 task->task_max_xfer_len = fds->fds_max_sgl_xfer_len;
1778 1777 /*
1779 1778 * A single stream load encounters a little extra
1780 1779 * latency if large xfers are done in 1 chunk.
1781 1780 * Give a hint to the LU that starting the xfer
1782 1781 * with a smaller chunk would be better in this case.
1783 1782 * For any other load, use maximum chunk size.
1784 1783 */
1785 1784 if (load == 1) {
1786 1785 /* estimate */
1787 1786 task->task_1st_xfer_len = 128*1024;
1788 1787 } else {
1789 1788 /* zero means no hint */
1790 1789 task->task_1st_xfer_len = 0;
1791 1790 }
1792 1791 }
1793 1792
1794 1793 stmf_post_task((scsi_task_t *)cmd->cmd_specific, dbuf);
1795 1794 atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_TRANSITION);
1796 1795 return;
1797 1796 }
1798 1797 /* We dont need dbuf for other cmds */
1799 1798 if (dbuf) {
1800 1799 cmd->cmd_port->port_fds->fds_free_data_buf(
1801 1800 cmd->cmd_port->port_fds, dbuf);
1802 1801 dbuf = NULL;
1803 1802 }
1804 1803 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1805 1804 fct_handle_els(cmd);
1806 1805 return;
1807 1806 }
1808 1807 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
1809 1808 fct_handle_rcvd_abts(cmd);
1810 1809 return;
1811 1810 }
1812 1811
1813 1812 ASSERT(0);
1814 1813 }
1815 1814
1816 1815 /*
1817 1816 * This function bypasses fct_handle_els()
1818 1817 */
1819 1818 void
1820 1819 fct_post_implicit_logo(fct_cmd_t *cmd)
1821 1820 {
1822 1821 fct_local_port_t *port = cmd->cmd_port;
1823 1822 fct_i_local_port_t *iport =
1824 1823 (fct_i_local_port_t *)port->port_fct_private;
1825 1824 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1826 1825 fct_remote_port_t *rp = cmd->cmd_rp;
1827 1826 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1828 1827
1829 1828 icmd->icmd_start_time = ddi_get_lbolt();
1830 1829
1831 1830 rw_enter(&irp->irp_lock, RW_WRITER);
1832 1831 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
1833 1832 atomic_inc_16(&irp->irp_nonfcp_xchg_count);
1834 1833 atomic_inc_16(&irp->irp_sa_elses_count);
1835 1834 /*
1836 1835 * An implicit LOGO can also be posted to a irp where a PLOGI might
1837 1836 * be in process. That PLOGI will reset this flag and decrement the
1838 1837 * iport_nrps_login counter.
1839 1838 */
1840 1839 if (irp->irp_flags & IRP_PLOGI_DONE) {
1841 1840 atomic_dec_32(&iport->iport_nrps_login);
1842 1841 }
1843 1842 atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1844 1843 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1845 1844 fct_post_to_discovery_queue(iport, irp, icmd);
1846 1845 rw_exit(&irp->irp_lock);
1847 1846 }
1848 1847
1849 1848 /*
1850 1849 * called with iport_lock held, return the slot number
1851 1850 */
1852 1851 uint16_t
1853 1852 fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd)
1854 1853 {
1855 1854 uint16_t cmd_slot;
1856 1855 uint32_t old, new;
1857 1856 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1858 1857
1859 1858 do {
1860 1859 old = iport->iport_next_free_slot;
1861 1860 cmd_slot = old & 0xFFFF;
1862 1861 if (cmd_slot == FCT_SLOT_EOL)
1863 1862 return (cmd_slot);
1864 1863 /*
1865 1864 * We use high order 16 bits as a counter which keeps on
1866 1865 * incrementing to avoid ABA issues with atomic lists.
1867 1866 */
1868 1867 new = ((old + (0x10000)) & 0xFFFF0000);
1869 1868 new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1870 1869 } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1871 1870
1872 1871 atomic_dec_16(&iport->iport_nslots_free);
1873 1872 iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1874 1873 cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1875 1874 (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1876 1875 << 24);
1877 1876 return (cmd_slot);
1878 1877 }
1879 1878
1880 1879 /*
1881 1880 * If icmd is not NULL, irp_lock must be held
1882 1881 */
1883 1882 void
1884 1883 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1885 1884 fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1886 1885 {
1887 1886 fct_i_cmd_t **p;
1888 1887
1889 1888 ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1890 1889 if (icmd) {
1891 1890 icmd->icmd_next = NULL;
1892 1891 for (p = &irp->irp_els_list; *p != NULL;
1893 1892 p = &((*p)->icmd_next))
1894 1893 ;
1895 1894
1896 1895 *p = icmd;
1897 1896 atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
1898 1897 }
1899 1898
1900 1899 mutex_enter(&iport->iport_worker_lock);
1901 1900 if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1902 1901
1903 1902 /*
1904 1903 * CAUTION: do not grab local_port/remote_port locks after
1905 1904 * grabbing the worker lock.
1906 1905 */
1907 1906 irp->irp_discovery_next = NULL;
1908 1907 if (iport->iport_rpwe_tail) {
1909 1908 iport->iport_rpwe_tail->irp_discovery_next = irp;
1910 1909 iport->iport_rpwe_tail = irp;
1911 1910 } else {
1912 1911 iport->iport_rpwe_head = iport->iport_rpwe_tail = irp;
1913 1912 }
1914 1913
1915 1914 atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE);
1916 1915 }
1917 1916
1918 1917 /*
1919 1918 * We need always signal the port worker irrespective of the fact that
1920 1919 * irp is already in discovery queue or not.
1921 1920 */
1922 1921 if (IS_WORKER_SLEEPING(iport)) {
1923 1922 cv_signal(&iport->iport_worker_cv);
1924 1923 }
1925 1924 mutex_exit(&iport->iport_worker_lock);
1926 1925 }
1927 1926
1928 1927 stmf_status_t
1929 1928 fct_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
1930 1929 {
1931 1930 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1932 1931
1933 1932 DTRACE_FC_5(xfer__start,
1934 1933 fct_cmd_t, cmd,
1935 1934 fct_i_local_port_t, cmd->cmd_port->port_fct_private,
1936 1935 scsi_task_t, task,
1937 1936 fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
1938 1937 stmf_data_buf_t, dbuf);
1939 1938
1940 1939 return (cmd->cmd_port->port_xfer_scsi_data(cmd, dbuf, ioflags));
1941 1940 }
1942 1941
1943 1942 void
1944 1943 fct_scsi_data_xfer_done(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
1945 1944 {
1946 1945 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1947 1946 uint32_t old, new;
1948 1947 uint32_t iof = 0;
1949 1948
1950 1949 DTRACE_FC_5(xfer__done,
1951 1950 fct_cmd_t, cmd,
1952 1951 fct_i_local_port_t, cmd->cmd_port->port_fct_private,
1953 1952 scsi_task_t, ((scsi_task_t *)cmd->cmd_specific),
1954 1953 fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
1955 1954 stmf_data_buf_t, dbuf);
1956 1955
1957 1956 if (ioflags & FCT_IOF_FCA_DONE) {
1958 1957 do {
1959 1958 old = new = icmd->icmd_flags;
1960 1959 if (old & ICMD_BEING_ABORTED) {
1961 1960 return;
1962 1961 }
1963 1962 new &= ~ICMD_KNOWN_TO_FCA;
1964 1963 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
1965 1964 iof = STMF_IOF_LPORT_DONE;
1966 1965 cmd->cmd_comp_status = dbuf->db_xfer_status;
1967 1966 }
1968 1967
1969 1968 if (icmd->icmd_flags & ICMD_BEING_ABORTED)
1970 1969 return;
1971 1970 stmf_data_xfer_done((scsi_task_t *)cmd->cmd_specific, dbuf, iof);
1972 1971 }
1973 1972
1974 1973 stmf_status_t
1975 1974 fct_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
1976 1975 {
1977 1976 fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
1978 1977
1979 1978 DTRACE_FC_4(scsi__response,
1980 1979 fct_cmd_t, cmd,
1981 1980 fct_i_local_port_t,
1982 1981 (fct_i_local_port_t *)cmd->cmd_port->port_fct_private,
1983 1982 scsi_task_t, task,
1984 1983 fct_i_remote_port_t,
1985 1984 (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private);
1986 1985
1987 1986 return (cmd->cmd_port->port_send_cmd_response(cmd, ioflags));
1988 1987 }
1989 1988
1990 1989 void
1991 1990 fct_send_response_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
1992 1991 {
1993 1992 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1994 1993 fct_local_port_t *port = cmd->cmd_port;
1995 1994 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1996 1995 port->port_fct_private;
1997 1996 uint32_t old, new;
1998 1997
1999 1998 if ((ioflags & FCT_IOF_FCA_DONE) == 0) {
2000 1999 /* Until we support confirmed completions, this is an error */
2001 2000 fct_queue_cmd_for_termination(cmd, s);
2002 2001 return;
2003 2002 }
2004 2003 do {
2005 2004 old = new = icmd->icmd_flags;
2006 2005 if (old & ICMD_BEING_ABORTED) {
2007 2006 return;
2008 2007 }
2009 2008 new &= ~ICMD_KNOWN_TO_FCA;
2010 2009 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2011 2010
2012 2011 cmd->cmd_comp_status = s;
2013 2012 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2014 2013 stmf_send_status_done((scsi_task_t *)cmd->cmd_specific, s,
2015 2014 STMF_IOF_LPORT_DONE);
2016 2015 return;
2017 2016 }
2018 2017
2019 2018 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
2020 2019 fct_cmd_free(cmd);
2021 2020 return;
2022 2021 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
2023 2022 fct_handle_sol_els_completion(iport, icmd);
2024 2023 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
2025 2024 /* Tell the caller that we are done */
2026 2025 atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
2027 2026 } else {
2028 2027 ASSERT(0);
2029 2028 }
2030 2029 }
2031 2030
2032 2031 void
2033 2032 fct_cmd_free(fct_cmd_t *cmd)
2034 2033 {
2035 2034 char info[FCT_INFO_LEN];
2036 2035 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2037 2036 fct_local_port_t *port = cmd->cmd_port;
2038 2037 fct_i_local_port_t *iport = (fct_i_local_port_t *)
2039 2038 port->port_fct_private;
2040 2039 fct_i_remote_port_t *irp = NULL;
2041 2040 int do_abts_acc = 0;
2042 2041 uint32_t old, new;
2043 2042
2044 2043 ASSERT(!mutex_owned(&iport->iport_worker_lock));
2045 2044 /* Give the slot back */
2046 2045 if (CMD_HANDLE_VALID(cmd->cmd_handle)) {
2047 2046 uint16_t n = CMD_HANDLE_SLOT_INDEX(cmd->cmd_handle);
2048 2047 fct_cmd_slot_t *slot;
2049 2048
2050 2049 /*
2051 2050 * If anything went wrong, grab the lock as writer. This is
2052 2051 * probably unnecessary.
2053 2052 */
2054 2053 if ((cmd->cmd_comp_status != FCT_SUCCESS) ||
2055 2054 (icmd->icmd_flags & ICMD_ABTS_RECEIVED)) {
2056 2055 rw_enter(&iport->iport_lock, RW_WRITER);
2057 2056 } else {
2058 2057 rw_enter(&iport->iport_lock, RW_READER);
2059 2058 }
2060 2059
2061 2060 if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) &&
2062 2061 (cmd->cmd_link != NULL)) {
2063 2062 do_abts_acc = 1;
2064 2063 }
2065 2064
2066 2065 /* XXX Validate slot before freeing */
2067 2066
2068 2067 slot = &iport->iport_cmd_slots[n];
2069 2068 slot->slot_uniq_cntr++;
2070 2069 slot->slot_cmd = NULL;
2071 2070 do {
2072 2071 old = iport->iport_next_free_slot;
2073 2072 slot->slot_next = old & 0xFFFF;
2074 2073 new = (old + 0x10000) & 0xFFFF0000;
2075 2074 new |= slot->slot_no;
2076 2075 } while (atomic_cas_32(&iport->iport_next_free_slot,
2077 2076 old, new) != old);
2078 2077 cmd->cmd_handle = 0;
2079 2078 atomic_inc_16(&iport->iport_nslots_free);
2080 2079 if (cmd->cmd_rp) {
2081 2080 irp = (fct_i_remote_port_t *)
2082 2081 cmd->cmd_rp->rp_fct_private;
2083 2082 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2084 2083 atomic_dec_16(&irp->irp_fcp_xchg_count);
2085 2084 else
2086 2085 atomic_dec_16(&irp->irp_nonfcp_xchg_count);
2087 2086 }
2088 2087 rw_exit(&iport->iport_lock);
2089 2088 } else if ((icmd->icmd_flags & ICMD_IMPLICIT) &&
2090 2089 (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) {
2091 2090 /* for implicit cmd, no cmd slot is used */
2092 2091 if (cmd->cmd_rp) {
2093 2092 irp = (fct_i_remote_port_t *)
2094 2093 cmd->cmd_rp->rp_fct_private;
2095 2094 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2096 2095 atomic_dec_16(&irp->irp_fcp_xchg_count);
2097 2096 else
2098 2097 atomic_dec_16(&irp->irp_nonfcp_xchg_count);
2099 2098 }
2100 2099 }
2101 2100
2102 2101 if (do_abts_acc) {
2103 2102 fct_cmd_t *lcmd = cmd->cmd_link;
2104 2103 fct_fill_abts_acc(lcmd);
2105 2104 if (port->port_send_cmd_response(lcmd,
2106 2105 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2107 2106 /*
2108 2107 * XXX Throw HBA fatal error event
2109 2108 * Later shutdown svc will terminate the ABTS in the end
2110 2109 */
2111 2110 (void) snprintf(info, sizeof (info),
2112 2111 "fct_cmd_free: iport-%p, ABTS_ACC"
2113 2112 " port_send_cmd_response failed", (void *)iport);
2114 2113 (void) fct_port_shutdown(iport->iport_port,
2115 2114 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2116 2115 return;
2117 2116 } else {
2118 2117 fct_cmd_free(lcmd);
2119 2118 cmd->cmd_link = NULL;
2120 2119 }
2121 2120 }
2122 2121
2123 2122 /* Free the cmd */
2124 2123 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2125 2124 if (iport->iport_cached_ncmds < max_cached_ncmds) {
2126 2125 icmd->icmd_flags = 0;
2127 2126 mutex_enter(&iport->iport_cached_cmd_lock);
2128 2127 icmd->icmd_next = iport->iport_cached_cmdlist;
2129 2128 iport->iport_cached_cmdlist = icmd;
2130 2129 iport->iport_cached_ncmds++;
2131 2130 mutex_exit(&iport->iport_cached_cmd_lock);
2132 2131 } else {
2133 2132 atomic_dec_32(&iport->iport_total_alloced_ncmds);
2134 2133 fct_free(cmd);
2135 2134 }
2136 2135 } else {
2137 2136 fct_free(cmd);
2138 2137 }
2139 2138 }
2140 2139
2141 2140 /* ARGSUSED */
2142 2141 stmf_status_t
2143 2142 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2144 2143 uint32_t flags)
2145 2144 {
2146 2145 stmf_status_t ret = STMF_SUCCESS;
2147 2146 scsi_task_t *task;
2148 2147 fct_cmd_t *cmd;
2149 2148 fct_i_cmd_t *icmd;
2150 2149 fct_local_port_t *port;
2151 2150 uint32_t old, new;
2152 2151
2153 2152 ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK);
2154 2153
2155 2154 task = (scsi_task_t *)arg;
2156 2155 cmd = (fct_cmd_t *)task->task_port_private;
2157 2156 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2158 2157 port = (fct_local_port_t *)lport->lport_port_private;
2159 2158
2160 2159 do {
2161 2160 old = new = icmd->icmd_flags;
2162 2161 if ((old & ICMD_KNOWN_TO_FCA) == 0)
2163 2162 return (STMF_NOT_FOUND);
2164 2163 ASSERT((old & ICMD_FCA_ABORT_CALLED) == 0);
2165 2164 new |= ICMD_BEING_ABORTED | ICMD_FCA_ABORT_CALLED;
2166 2165 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2167 2166 ret = port->port_abort_cmd(port, cmd, 0);
2168 2167 if ((ret == FCT_NOT_FOUND) || (ret == FCT_ABORT_SUCCESS)) {
2169 2168 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2170 2169 } else if (ret == FCT_BUSY) {
2171 2170 atomic_and_32(&icmd->icmd_flags, ~ICMD_FCA_ABORT_CALLED);
2172 2171 }
2173 2172
2174 2173 return (ret);
2175 2174 }
2176 2175
2177 2176 void
2178 2177 fct_ctl(struct stmf_local_port *lport, int cmd, void *arg)
2179 2178 {
2180 2179 fct_local_port_t *port;
2181 2180 fct_i_local_port_t *iport;
2182 2181 stmf_change_status_t st;
2183 2182 stmf_change_status_t *pst;
2184 2183
2185 2184 ASSERT((cmd == STMF_CMD_LPORT_ONLINE) ||
2186 2185 (cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
2187 2186 (cmd == STMF_CMD_LPORT_OFFLINE) ||
2188 2187 (cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE) ||
2189 2188 (cmd == FCT_CMD_PORT_ONLINE_COMPLETE) ||
2190 2189 (cmd == FCT_CMD_PORT_OFFLINE_COMPLETE));
2191 2190
2192 2191 port = (fct_local_port_t *)lport->lport_port_private;
2193 2192 pst = (stmf_change_status_t *)arg;
2194 2193 st.st_completion_status = STMF_SUCCESS;
2195 2194 st.st_additional_info = NULL;
2196 2195
2197 2196 iport = (fct_i_local_port_t *)port->port_fct_private;
2198 2197 /*
2199 2198 * We are mostly a passthrough, except during offline.
2200 2199 */
2201 2200 switch (cmd) {
2202 2201 case STMF_CMD_LPORT_ONLINE:
2203 2202 if (iport->iport_state == FCT_STATE_ONLINE)
2204 2203 st.st_completion_status = STMF_ALREADY;
2205 2204 else if (iport->iport_state != FCT_STATE_OFFLINE)
2206 2205 st.st_completion_status = STMF_INVALID_ARG;
2207 2206 if (st.st_completion_status != STMF_SUCCESS) {
2208 2207 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport,
2209 2208 &st);
2210 2209 break;
2211 2210 }
2212 2211 iport->iport_state_not_acked = 1;
2213 2212 iport->iport_state = FCT_STATE_ONLINING;
2214 2213 port->port_ctl(port, FCT_CMD_PORT_ONLINE, arg);
2215 2214 break;
2216 2215 case FCT_CMD_PORT_ONLINE_COMPLETE:
2217 2216 ASSERT(iport->iport_state == FCT_STATE_ONLINING);
2218 2217 if (pst->st_completion_status != FCT_SUCCESS) {
2219 2218 iport->iport_state = FCT_STATE_OFFLINE;
2220 2219 iport->iport_state_not_acked = 0;
2221 2220 } else {
2222 2221 iport->iport_state = FCT_STATE_ONLINE;
2223 2222 }
2224 2223 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, arg);
2225 2224 break;
2226 2225 case STMF_ACK_LPORT_ONLINE_COMPLETE:
2227 2226 ASSERT(iport->iport_state == FCT_STATE_ONLINE);
2228 2227 iport->iport_state_not_acked = 0;
2229 2228 port->port_ctl(port, FCT_ACK_PORT_ONLINE_COMPLETE, arg);
2230 2229 break;
2231 2230
2232 2231 case STMF_CMD_LPORT_OFFLINE:
2233 2232 if (iport->iport_state == FCT_STATE_OFFLINE)
2234 2233 st.st_completion_status = STMF_ALREADY;
2235 2234 else if (iport->iport_state != FCT_STATE_ONLINE)
2236 2235 st.st_completion_status = STMF_INVALID_ARG;
2237 2236 if (st.st_completion_status != STMF_SUCCESS) {
2238 2237 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
2239 2238 &st);
2240 2239 break;
2241 2240 }
2242 2241 iport->iport_state_not_acked = 1;
2243 2242 iport->iport_state = FCT_STATE_OFFLINING;
2244 2243 port->port_ctl(port, FCT_CMD_PORT_OFFLINE, arg);
2245 2244 break;
2246 2245 case FCT_CMD_PORT_OFFLINE_COMPLETE:
2247 2246 ASSERT(iport->iport_state == FCT_STATE_OFFLINING);
2248 2247 if (pst->st_completion_status != FCT_SUCCESS) {
2249 2248 iport->iport_state = FCT_STATE_ONLINE;
2250 2249 iport->iport_state_not_acked = 0;
2251 2250 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
2252 2251 pst);
2253 2252 break;
2254 2253 }
2255 2254
2256 2255 /*
2257 2256 * If FCA's offline was successful, we dont tell stmf yet.
2258 2257 * Becasue now we have to do the cleanup before we go upto
2259 2258 * stmf. That cleanup is done by the worker thread.
2260 2259 */
2261 2260
2262 2261 /* FCA is offline, post a link down, its harmless anyway */
2263 2262 fct_handle_event(port, FCT_EVENT_LINK_DOWN, 0, 0);
2264 2263
2265 2264 /* Trigger port offline processing by the worker */
2266 2265 iport->iport_offline_prstate = FCT_OPR_START;
2267 2266 break;
2268 2267 case STMF_ACK_LPORT_OFFLINE_COMPLETE:
2269 2268 ASSERT(iport->iport_state == FCT_STATE_OFFLINE);
2270 2269 iport->iport_state_not_acked = 0;
2271 2270 port->port_ctl(port, FCT_ACK_PORT_OFFLINE_COMPLETE, arg);
2272 2271 break;
2273 2272 }
2274 2273 }
2275 2274
2276 2275 /* ARGSUSED */
2277 2276 stmf_status_t
2278 2277 fct_info(uint32_t cmd, stmf_local_port_t *lport, void *arg, uint8_t *buf,
2279 2278 uint32_t *bufsizep)
2280 2279 {
2281 2280 return (STMF_NOT_SUPPORTED);
2282 2281 }
2283 2282
2284 2283 /*
2285 2284 * implicit: if it's true, it means it will only be used in fct module, or else
2286 2285 * it will be sent to the link.
2287 2286 */
2288 2287 fct_cmd_t *
2289 2288 fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp, int implicit,
2290 2289 uchar_t elsop, uint32_t wkdid, fct_icmd_cb_t icmdcb)
2291 2290 {
2292 2291 fct_cmd_t *cmd = NULL;
2293 2292 fct_i_cmd_t *icmd = NULL;
2294 2293 fct_els_t *els = NULL;
2295 2294 fct_i_remote_port_t *irp = NULL;
2296 2295 uint8_t *p = NULL;
2297 2296 uint32_t ptid = 0;
2298 2297
2299 2298 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
2300 2299 port->port_fca_sol_els_private_size, 0);
2301 2300 if (!cmd) {
2302 2301 return (NULL);
2303 2302 }
2304 2303
2305 2304 if (rp) {
2306 2305 irp = RP_TO_IRP(rp);
2307 2306 } else if (((irp = fct_portid_to_portptr(PORT_TO_IPORT(port),
2308 2307 wkdid)) == NULL) && (elsop != ELS_OP_PLOGI)) {
2309 2308 stmf_trace(PORT_TO_IPORT(port)->iport_alias,
2310 2309 "fct_create_solels: Must PLOGI to %x first", wkdid);
2311 2310 fct_free(cmd);
2312 2311 return (NULL);
2313 2312 }
2314 2313
2315 2314 cmd->cmd_port = port;
2316 2315 cmd->cmd_oxid = PTR2INT(cmd, uint16_t);
2317 2316 cmd->cmd_rxid = 0xFFFF;
2318 2317 cmd->cmd_handle = 0;
2319 2318 icmd = CMD_TO_ICMD(cmd);
2320 2319 els = ICMD_TO_ELS(icmd);
2321 2320 icmd->icmd_cb = icmdcb;
2322 2321 if (irp) {
2323 2322 cmd->cmd_rp = irp->irp_rp;
2324 2323 cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
2325 2324 cmd->cmd_rportid = irp->irp_rp->rp_id;
2326 2325 } else {
2327 2326 cmd->cmd_rp_handle = FCT_HANDLE_NONE;
2328 2327 cmd->cmd_rportid = wkdid;
2329 2328 }
2330 2329 cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid;
2331 2330
2332 2331 if (implicit) {
2333 2332 /*
2334 2333 * Since we will not send it to FCA, so we only allocate space
2335 2334 */
2336 2335 ASSERT(elsop & (ELS_OP_LOGO | ELS_OP_PLOGI));
2337 2336 icmd->icmd_flags |= ICMD_IMPLICIT;
2338 2337 if (elsop == ELS_OP_LOGO) {
2339 2338 /*
2340 2339 * Handling implicit LOGO should dependent on as less
2341 2340 * as resources. So a trick here.
2342 2341 */
2343 2342 els->els_req_size = 1;
2344 2343 els->els_req_payload = cmd->cmd_fca_private;
2345 2344 } else {
2346 2345 els->els_req_alloc_size = els->els_req_size = 116;
2347 2346 els->els_resp_alloc_size = els->els_resp_size = 116;
2348 2347 els->els_req_payload = (uint8_t *)
2349 2348 kmem_zalloc(els->els_req_size, KM_SLEEP);
2350 2349 els->els_resp_payload = (uint8_t *)
2351 2350 kmem_zalloc(els->els_resp_size, KM_SLEEP);
2352 2351 }
2353 2352 } else {
2354 2353 /*
2355 2354 * Allocate space for its request and response
2356 2355 * Fill the request payload according to spec.
2357 2356 */
2358 2357 switch (elsop) {
2359 2358 case ELS_OP_LOGO:
2360 2359 els->els_resp_alloc_size = els->els_resp_size = 4;
2361 2360 els->els_resp_payload = (uint8_t *)kmem_zalloc(
2362 2361 els->els_resp_size, KM_SLEEP);
2363 2362 els->els_req_alloc_size = els->els_req_size = 16;
2364 2363 els->els_req_payload = (uint8_t *)kmem_zalloc(
2365 2364 els->els_req_size, KM_SLEEP);
2366 2365 ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2367 2366 fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2368 2367 bcopy(port->port_pwwn, els->els_req_payload + 8, 8);
2369 2368 break;
2370 2369
2371 2370 case ELS_OP_RSCN:
2372 2371 els->els_resp_alloc_size = els->els_resp_size = 4;
2373 2372 els->els_resp_payload = (uint8_t *)kmem_zalloc(
2374 2373 els->els_resp_size, KM_SLEEP);
2375 2374 els->els_req_size = els->els_req_alloc_size = 8;
2376 2375 els->els_req_payload = (uint8_t *)kmem_zalloc(
2377 2376 els->els_req_size, KM_SLEEP);
2378 2377 els->els_req_payload[1] = 0x04;
2379 2378 els->els_req_payload[3] = 0x08;
2380 2379 els->els_req_payload[4] |= 0x80;
2381 2380 ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2382 2381 fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2383 2382 break;
2384 2383
2385 2384 case ELS_OP_PLOGI:
2386 2385 els->els_resp_alloc_size = els->els_resp_size = 116;
2387 2386 els->els_resp_payload = (uint8_t *)
2388 2387 kmem_zalloc(els->els_resp_size, KM_SLEEP);
2389 2388 els->els_req_alloc_size = els->els_req_size = 116;
2390 2389 p = els->els_req_payload = (uint8_t *)
2391 2390 kmem_zalloc(els->els_req_size, KM_SLEEP);
2392 2391 bcopy(port->port_pwwn, p + 20, 8);
2393 2392 bcopy(port->port_nwwn, p + 28, 8);
2394 2393
2395 2394 /*
2396 2395 * Common service parameters
2397 2396 */
2398 2397 p[0x04] = 0x09; /* high version */
2399 2398 p[0x05] = 0x08; /* low version */
2400 2399 p[0x06] = 0x00; /* BB credit: 0x0065 */
2401 2400 p[0x07] = 0x65;
2402 2401
2403 2402 /* CI0: Continuously Increasing Offset - 1 */
2404 2403 /* RRO: Randomly Relative Offset - 0 */
2405 2404 /* VVV: Vendor Version Level - 0 */
2406 2405 /* N-F: N or F Port Payload Sender - 0 (N) */
2407 2406 /* BBM: BB Credit Management - 0 (Normal) */
2408 2407 p[0x08] = 0x80;
2409 2408 p[0x09] = 0x00;
2410 2409
2411 2410 /* Max RX size */
2412 2411 p[0x0A] = 0x08;
2413 2412 p[0x0B] = 0x00;
2414 2413
2415 2414 /* NPTCS: N Port Total Concurrent Sequences - 0x0000 */
2416 2415 p[0x0C] = 0x00;
2417 2416 p[0x0D] = 0x00;
2418 2417
2419 2418 /* ROIC: Relative Offset By Info - 0xFFFF */
2420 2419 p[0x0E] = 0xFF;
2421 2420 p[0x0F] = 0xFF;
2422 2421
2423 2422 /* EDTOV: Error Detect Timeout - 0x000007D0 */
2424 2423 p[0x10] = 0x00;
2425 2424 p[0x11] = 0x00;
2426 2425 p[0x12] = 0x07;
2427 2426 p[0x13] = 0xD0;
2428 2427
2429 2428 /*
2430 2429 * Class-3 Parameters
2431 2430 */
2432 2431 /* C3-VAL: Class 3 Value - 1 */
2433 2432 /* C3-XID: X_ID Reassignment - 0 */
2434 2433 /* C3-IPA: Initial Process Assignment */
2435 2434 /* C3-AI-DCC: Data compression capable */
2436 2435 /* C3-AI-DC-HB: Data compression history buffer size */
2437 2436 /* C3-AI-DCE: Data encrytion capable */
2438 2437 /* C3-AI-CSC: Clock synchronization capable */
2439 2438 /* C3-ErrPol: Error pliciy */
2440 2439 /* C3-CatSeq: Information Cat. Per Sequence */
2441 2440 /* C3-AR-DCC: */
2442 2441 /* C3-AR-DC-HB: */
2443 2442 /* C3-AR-DCE: */
2444 2443 /* C3-AR-CSC */
2445 2444 p[0x44] = 0x80;
2446 2445 p[0x45] = 0x00;
2447 2446 p[0x46] = 0x00;
2448 2447 p[0x47] = 0x00;
2449 2448 p[0x48] = 0x00;
2450 2449 p[0x49] = 0x00;
2451 2450
2452 2451 /* C3-RxSize: Class 3 receive data size */
2453 2452 p[0x4A] = 0x08;
2454 2453 p[0x4B] = 0x00;
2455 2454
2456 2455 /* C3-ConSeq: Class 3 Concourrent sequences */
2457 2456 p[0x4C] = 0x00;
2458 2457 p[0x4D] = 0xFF;
2459 2458
2460 2459 /* C3-OSPE: Class 3 open sequence per exchange */
2461 2460 p[0x50] = 0x00;
2462 2461 p[0x51] = 0x01;
2463 2462
2464 2463 break;
2465 2464
2466 2465 case ELS_OP_SCR:
2467 2466 els->els_resp_alloc_size = els->els_resp_size = 4;
2468 2467 els->els_resp_payload = (uint8_t *)
2469 2468 kmem_zalloc(els->els_resp_size, KM_SLEEP);
2470 2469 els->els_req_alloc_size = els->els_req_size = 8;
2471 2470 p = els->els_req_payload = (uint8_t *)
2472 2471 kmem_zalloc(els->els_req_size, KM_SLEEP);
2473 2472 p[7] = FC_SCR_FULL_REGISTRATION;
2474 2473 break;
2475 2474 case ELS_OP_RLS:
2476 2475 els->els_resp_alloc_size = els->els_resp_size = 28;
2477 2476 els->els_resp_payload = (uint8_t *)
2478 2477 kmem_zalloc(els->els_resp_size, KM_SLEEP);
2479 2478 els->els_req_alloc_size = els->els_req_size = 8;
2480 2479 p = els->els_req_payload = (uint8_t *)
2481 2480 kmem_zalloc(els->els_req_size, KM_SLEEP);
2482 2481 ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
2483 2482 fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
2484 2483 break;
2485 2484
2486 2485 default:
2487 2486 ASSERT(0);
2488 2487 }
2489 2488 }
2490 2489
2491 2490 els->els_req_payload[0] = elsop;
2492 2491 return (cmd);
2493 2492 }
2494 2493
2495 2494 fct_cmd_t *
2496 2495 fct_create_solct(fct_local_port_t *port, fct_remote_port_t *query_rp,
2497 2496 uint16_t ctop, fct_icmd_cb_t icmdcb)
2498 2497 {
2499 2498 fct_cmd_t *cmd = NULL;
2500 2499 fct_i_cmd_t *icmd = NULL;
2501 2500 fct_sol_ct_t *ct = NULL;
2502 2501 uint8_t *p = NULL;
2503 2502 fct_i_remote_port_t *irp = NULL;
2504 2503 fct_i_local_port_t *iport = NULL;
2505 2504 char *nname = NULL;
2506 2505 int namelen = 0;
2507 2506
2508 2507 /*
2509 2508 * Allocate space
2510 2509 */
2511 2510 cmd = fct_alloc(FCT_STRUCT_CMD_SOL_CT,
2512 2511 port->port_fca_sol_ct_private_size, 0);
2513 2512 if (!cmd) {
2514 2513 return (NULL);
2515 2514 }
2516 2515
2517 2516 /*
2518 2517 * We should have PLOGIed to the name server (0xFFFFFC)
2519 2518 * Caution: this irp is not query_rp->rp_fct_private.
2520 2519 */
2521 2520 irp = fct_portid_to_portptr((fct_i_local_port_t *)
2522 2521 port->port_fct_private, FS_NAME_SERVER);
2523 2522 if (irp == NULL) {
2524 2523 stmf_trace(PORT_TO_IPORT(port)->iport_alias,
2525 2524 "fct_create_solct: Must PLOGI name server first");
2526 2525 fct_free(cmd);
2527 2526 return (NULL);
2528 2527 }
2529 2528
2530 2529 cmd->cmd_port = port;
2531 2530 cmd->cmd_rp = irp->irp_rp;
2532 2531 cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
2533 2532 cmd->cmd_rportid = irp->irp_rp->rp_id;
2534 2533 cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid;
2535 2534 cmd->cmd_oxid = PTR2INT(cmd, uint16_t);
2536 2535 cmd->cmd_rxid = 0xFFFF;
2537 2536 cmd->cmd_handle = 0;
2538 2537 icmd = CMD_TO_ICMD(cmd);
2539 2538 ct = ICMD_TO_CT(icmd);
2540 2539 icmd->icmd_cb = icmdcb;
2541 2540 iport = ICMD_TO_IPORT(icmd);
2542 2541
2543 2542 switch (ctop) {
2544 2543 case NS_GSNN_NN:
2545 2544 /*
2546 2545 * Allocate max space for its sybolic name
2547 2546 */
2548 2547 ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
2549 2548 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2550 2549 KM_SLEEP);
2551 2550
2552 2551 ct->ct_req_size = ct->ct_req_alloc_size = 24;
2553 2552 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2554 2553 KM_SLEEP);
2555 2554
2556 2555 bcopy(query_rp->rp_nwwn, p + 16, 8);
2557 2556 break;
2558 2557
2559 2558 case NS_RNN_ID:
2560 2559 ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2561 2560 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2562 2561 KM_SLEEP);
2563 2562 ct->ct_req_size = ct->ct_req_alloc_size = 28;
2564 2563 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2565 2564 KM_SLEEP);
2566 2565
2567 2566 /*
2568 2567 * Port Identifier
2569 2568 */
2570 2569 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2571 2570 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF;
2572 2571 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF;
2573 2572
2574 2573 /*
2575 2574 * Node Name
2576 2575 */
2577 2576 bcopy(port->port_nwwn, p + 20, 8);
2578 2577 break;
2579 2578
2580 2579 case NS_RCS_ID:
2581 2580 ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2582 2581 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2583 2582 KM_SLEEP);
2584 2583 ct->ct_req_size = ct->ct_req_alloc_size = 24;
2585 2584 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2586 2585 KM_SLEEP);
2587 2586
2588 2587 /*
2589 2588 * Port Identifier
2590 2589 */
2591 2590 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2592 2591 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF;
2593 2592 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF;
2594 2593
2595 2594 /*
2596 2595 * Class of Service
2597 2596 */
2598 2597 *(p + 23) = FC_NS_CLASS3;
2599 2598 break;
2600 2599
2601 2600 case NS_RFT_ID:
2602 2601 ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2603 2602 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2604 2603 KM_SLEEP);
2605 2604 ct->ct_req_size = ct->ct_req_alloc_size = 52;
2606 2605 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2607 2606 KM_SLEEP);
2608 2607
2609 2608 /*
2610 2609 * Port Identifier
2611 2610 */
2612 2611 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2613 2612 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF;
2614 2613 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF;
2615 2614
2616 2615 /*
2617 2616 * FC-4 Protocol Types
2618 2617 */
2619 2618 *(p + 22) = 0x1; /* 0x100 */
2620 2619 break;
2621 2620
2622 2621 case NS_RSPN_ID:
2623 2622 /*
2624 2623 * If we get here, port->port_sym_port_name is always not NULL.
2625 2624 */
2626 2625 ASSERT(port->port_sym_port_name);
2627 2626 namelen = strlen(port->port_sym_port_name);
2628 2627 ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2629 2628 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2630 2629 KM_SLEEP);
2631 2630 ct->ct_req_size = ct->ct_req_alloc_size =
2632 2631 (21 + namelen + 3) & ~3;
2633 2632 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2634 2633 KM_SLEEP);
2635 2634
2636 2635 /*
2637 2636 * Port Identifier
2638 2637 */
2639 2638 p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
2640 2639 p[18] = (iport->iport_link_info.portid >> 8) & 0xFF;
2641 2640 p[19] = (iport->iport_link_info.portid >> 0) & 0xFF;
2642 2641
2643 2642 /*
2644 2643 * String length
2645 2644 */
2646 2645 p[20] = namelen;
2647 2646
2648 2647 /*
2649 2648 * Symbolic port name
2650 2649 */
2651 2650 bcopy(port->port_sym_port_name, p + 21, ct->ct_req_size - 21);
2652 2651 break;
2653 2652
2654 2653 case NS_RSNN_NN:
2655 2654 namelen = port->port_sym_node_name == NULL ?
2656 2655 strlen(utsname.nodename) :
2657 2656 strlen(port->port_sym_node_name);
2658 2657 nname = port->port_sym_node_name == NULL ?
2659 2658 utsname.nodename : port->port_sym_node_name;
2660 2659
2661 2660 ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
2662 2661 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2663 2662 KM_SLEEP);
2664 2663 ct->ct_req_size = ct->ct_req_alloc_size =
2665 2664 (25 + namelen + 3) & ~3;
2666 2665 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2667 2666 KM_SLEEP);
2668 2667
2669 2668 /*
2670 2669 * Node name
2671 2670 */
2672 2671 bcopy(port->port_nwwn, p + 16, 8);
2673 2672
2674 2673 /*
2675 2674 * String length
2676 2675 */
2677 2676 p[24] = namelen;
2678 2677
2679 2678 /*
2680 2679 * Symbolic node name
2681 2680 */
2682 2681 bcopy(nname, p + 25, ct->ct_req_size - 25);
2683 2682 break;
2684 2683
2685 2684 case NS_GSPN_ID:
2686 2685 ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
2687 2686 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2688 2687 KM_SLEEP);
2689 2688 ct->ct_req_size = ct->ct_req_alloc_size = 20;
2690 2689 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2691 2690 KM_SLEEP);
2692 2691 /*
2693 2692 * Port Identifier
2694 2693 */
2695 2694 p[17] = (query_rp->rp_id >> 16) & 0xFF;
2696 2695 p[18] = (query_rp->rp_id >> 8) & 0xFF;
2697 2696 p[19] = (query_rp->rp_id >> 0) & 0xFF;
2698 2697 break;
2699 2698
2700 2699 case NS_GCS_ID:
2701 2700 ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
2702 2701 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2703 2702 KM_SLEEP);
2704 2703 ct->ct_req_size = ct->ct_req_alloc_size = 20;
2705 2704 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2706 2705 KM_SLEEP);
2707 2706 /*
2708 2707 * Port Identifier
2709 2708 */
2710 2709 p[17] = (query_rp->rp_id >> 16) & 0xFF;
2711 2710 p[18] = (query_rp->rp_id >> 8) & 0xFF;
2712 2711 p[19] = (query_rp->rp_id >> 0) & 0xFF;
2713 2712 break;
2714 2713
2715 2714 case NS_GFT_ID:
2716 2715 ct->ct_resp_alloc_size = ct->ct_resp_size = 48;
2717 2716 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2718 2717 KM_SLEEP);
2719 2718 ct->ct_req_size = ct->ct_req_alloc_size = 20;
2720 2719 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2721 2720 KM_SLEEP);
2722 2721 /*
2723 2722 * Port Identifier
2724 2723 */
2725 2724 p[17] = (query_rp->rp_id >> 16) & 0xFF;
2726 2725 p[18] = (query_rp->rp_id >> 8) & 0xFF;
2727 2726 p[19] = (query_rp->rp_id >> 0) & 0xFF;
2728 2727 break;
2729 2728
2730 2729 case NS_GID_PN:
2731 2730 ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
2732 2731 ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
2733 2732 KM_SLEEP);
2734 2733
2735 2734 ct->ct_req_size = ct->ct_req_alloc_size = 24;
2736 2735 p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
2737 2736 KM_SLEEP);
2738 2737
2739 2738 bcopy(query_rp->rp_pwwn, p + 16, 8);
2740 2739 break;
2741 2740
2742 2741 default:
2743 2742 /* CONSTCOND */
2744 2743 ASSERT(0);
2745 2744 }
2746 2745
2747 2746 FCT_FILL_CTIU_PREAMBLE(p, ctop);
2748 2747 return (cmd);
2749 2748 }
2750 2749
2751 2750 /*
2752 2751 * Cmd can only be solicited CT/ELS. They will be dispatched to the discovery
2753 2752 * queue eventually too.
2754 2753 * We queue solicited cmds here to track solicited cmds and to take full use
2755 2754 * of single thread mechanism.
2756 2755 * But in current implmentation, we don't use this mechanism on SOL_CT, PLOGI.
2757 2756 * To avoid to interrupt current flow, ICMD_IN_SOLCMD_QUEUE is used here.
2758 2757 */
2759 2758 void
2760 2759 fct_post_to_solcmd_queue(fct_local_port_t *port, fct_cmd_t *cmd)
2761 2760 {
2762 2761 fct_i_local_port_t *iport = (fct_i_local_port_t *)
2763 2762 port->port_fct_private;
2764 2763 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2765 2764
2766 2765 mutex_enter(&iport->iport_worker_lock);
2767 2766 icmd->icmd_solcmd_next = iport->iport_solcmd_queue;
2768 2767 iport->iport_solcmd_queue = icmd;
2769 2768 atomic_or_32(&icmd->icmd_flags, ICMD_IN_SOLCMD_QUEUE | ICMD_SOLCMD_NEW);
2770 2769 if (IS_WORKER_SLEEPING(iport)) {
2771 2770 cv_signal(&iport->iport_worker_cv);
2772 2771 }
2773 2772 mutex_exit(&iport->iport_worker_lock);
2774 2773 }
2775 2774
2776 2775 /* ARGSUSED */
2777 2776 void
2778 2777 fct_event_handler(stmf_local_port_t *lport, int eventid, void *arg,
2779 2778 uint32_t flags)
2780 2779 {
2781 2780 fct_local_port_t *port = (fct_local_port_t *)
2782 2781 lport->lport_port_private;
2783 2782 fct_i_local_port_t *iport = (fct_i_local_port_t *)
2784 2783 port->port_fct_private;
2785 2784 stmf_scsi_session_t *ss;
2786 2785 fct_i_remote_port_t *irp;
2787 2786
2788 2787 switch (eventid) {
2789 2788 case LPORT_EVENT_INITIAL_LUN_MAPPED:
2790 2789 ss = (stmf_scsi_session_t *)arg;
2791 2790 irp = (fct_i_remote_port_t *)ss->ss_port_private;
2792 2791 stmf_trace(iport->iport_alias,
2793 2792 "Initial LUN mapped to session ss-%p, irp-%p", ss, irp);
2794 2793 break;
2795 2794
2796 2795 default:
2797 2796 stmf_trace(iport->iport_alias,
2798 2797 "Unknown event received, %d", eventid);
2799 2798 }
2800 2799 }
2801 2800
2802 2801 void
2803 2802 fct_send_cmd_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
2804 2803 {
2805 2804 /* XXX For now just call send_resp_done() */
2806 2805 fct_send_response_done(cmd, s, ioflags);
2807 2806 }
2808 2807
2809 2808 void
2810 2809 fct_cmd_fca_aborted(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
2811 2810 {
2812 2811 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2813 2812 char info[FCT_INFO_LEN];
2814 2813 unsigned long long st;
2815 2814
2816 2815 st = s; /* To make gcc happy */
2817 2816 ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED);
2818 2817 if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
2819 2818 ((ioflags & FCT_IOF_FCA_DONE) == 0)) {
2820 2819 (void) snprintf(info, sizeof (info),
2821 2820 "fct_cmd_fca_aborted: cmd-%p, "
2822 2821 "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags);
2823 2822 (void) fct_port_shutdown(cmd->cmd_port,
2824 2823 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2825 2824 return;
2826 2825 }
2827 2826
2828 2827 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2829 2828 /* For non FCP Rest of the work is done by the terminator */
2830 2829 /* For FCP stuff just call stmf */
2831 2830 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2832 2831 stmf_task_lport_aborted((scsi_task_t *)cmd->cmd_specific,
2833 2832 s, STMF_IOF_LPORT_DONE);
2834 2833 }
2835 2834 }
2836 2835
2837 2836 /*
2838 2837 * FCA drivers will use it, when they want to abort some FC transactions
2839 2838 * due to lack of resource.
2840 2839 */
2841 2840 uint16_t
2842 2841 fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid)
2843 2842 {
2844 2843 fct_i_remote_port_t *irp;
2845 2844
2846 2845 irp = fct_portid_to_portptr(
2847 2846 (fct_i_local_port_t *)(port->port_fct_private), rportid);
2848 2847 if (irp == NULL) {
2849 2848 return (0xFFFF);
2850 2849 } else {
2851 2850 return (irp->irp_rp->rp_handle);
2852 2851 }
2853 2852 }
2854 2853
2855 2854 fct_cmd_t *
2856 2855 fct_handle_to_cmd(fct_local_port_t *port, uint32_t fct_handle)
2857 2856 {
2858 2857 fct_cmd_slot_t *slot;
2859 2858 uint16_t ndx;
2860 2859
2861 2860 if (!CMD_HANDLE_VALID(fct_handle))
2862 2861 return (NULL);
2863 2862 if ((ndx = CMD_HANDLE_SLOT_INDEX(fct_handle)) >= port->port_max_xchges)
2864 2863 return (NULL);
2865 2864
2866 2865 slot = &((fct_i_local_port_t *)port->port_fct_private)->iport_cmd_slots[
2867 2866 ndx];
2868 2867
2869 2868 if ((slot->slot_uniq_cntr | 0x80) != (fct_handle >> 24))
2870 2869 return (NULL);
2871 2870 return (slot->slot_cmd->icmd_cmd);
2872 2871 }
2873 2872
2874 2873 void
2875 2874 fct_queue_scsi_task_for_termination(fct_cmd_t *cmd, fct_status_t s)
2876 2875 {
2877 2876 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2878 2877
2879 2878 uint32_t old, new;
2880 2879
2881 2880 do {
2882 2881 old = icmd->icmd_flags;
2883 2882 if ((old & (ICMD_BEING_ABORTED | ICMD_KNOWN_TO_FCA)) !=
2884 2883 ICMD_KNOWN_TO_FCA)
2885 2884 return;
2886 2885 new = old | ICMD_BEING_ABORTED;
2887 2886 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2888 2887 stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific,
2889 2888 s, NULL);
2890 2889 }
2891 2890
2892 2891 void
2893 2892 fct_fill_abts_acc(fct_cmd_t *cmd)
2894 2893 {
2895 2894 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
2896 2895 uint8_t *p;
2897 2896
2898 2897 abts->abts_resp_rctl = BLS_OP_BA_ACC;
2899 2898 p = abts->abts_resp_payload;
2900 2899 bzero(p, 12);
2901 2900 *((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid);
2902 2901 *((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid);
2903 2902 p[10] = p[11] = 0xff;
2904 2903 }
2905 2904
2906 2905 void
2907 2906 fct_handle_rcvd_abts(fct_cmd_t *cmd)
2908 2907 {
2909 2908 char info[FCT_INFO_LEN];
2910 2909 fct_local_port_t *port = cmd->cmd_port;
2911 2910 fct_i_local_port_t *iport =
2912 2911 (fct_i_local_port_t *)port->port_fct_private;
2913 2912 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2914 2913 fct_i_remote_port_t *irp;
2915 2914 fct_cmd_t *c = NULL;
2916 2915 fct_i_cmd_t *ic = NULL;
2917 2916 int found = 0;
2918 2917 int i;
2919 2918
2920 2919 icmd->icmd_start_time = ddi_get_lbolt();
2921 2920 icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
2922 2921
2923 2922 rw_enter(&iport->iport_lock, RW_WRITER);
2924 2923 /* Make sure local port is sane */
2925 2924 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2926 2925 rw_exit(&iport->iport_lock);
2927 2926 stmf_trace(iport->iport_alias, "ABTS not posted becasue"
2928 2927 "port state was %x", iport->iport_link_state);
2929 2928 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2930 2929 return;
2931 2930 }
2932 2931
2933 2932 if (cmd->cmd_rp_handle == FCT_HANDLE_NONE)
2934 2933 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
2935 2934 else if (cmd->cmd_rp_handle < port->port_max_logins)
2936 2935 irp = iport->iport_rp_slots[cmd->cmd_rp_handle];
2937 2936 else
2938 2937 irp = NULL;
2939 2938 if (irp == NULL) {
2940 2939 /* XXX Throw a logout to the initiator */
2941 2940 rw_exit(&iport->iport_lock);
2942 2941 stmf_trace(iport->iport_alias, "ABTS received from"
2943 2942 " %x without a session", cmd->cmd_rportid);
2944 2943 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
2945 2944 return;
2946 2945 }
2947 2946
2948 2947 DTRACE_FC_3(abts__receive,
2949 2948 fct_cmd_t, cmd,
2950 2949 fct_local_port_t, port,
2951 2950 fct_i_remote_port_t, irp);
2952 2951
2953 2952 cmd->cmd_rp = irp->irp_rp;
2954 2953
2955 2954 /*
2956 2955 * No need to allocate an xchg resource. ABTSes use the same
2957 2956 * xchg resource as the cmd they are aborting.
2958 2957 */
2959 2958 rw_enter(&irp->irp_lock, RW_WRITER);
2960 2959 mutex_enter(&iport->iport_worker_lock);
2961 2960 /* Lets find the command first */
2962 2961 for (i = 0; i < port->port_max_xchges; i++) {
2963 2962 if ((ic = iport->iport_cmd_slots[i].slot_cmd) == NULL)
2964 2963 continue;
2965 2964 if ((ic->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
2966 2965 continue;
2967 2966 c = ic->icmd_cmd;
2968 2967 if (!CMD_HANDLE_VALID(c->cmd_handle))
2969 2968 continue;
2970 2969 if ((c->cmd_rportid != cmd->cmd_rportid) ||
2971 2970 (c->cmd_oxid != cmd->cmd_oxid))
2972 2971 continue;
2973 2972 /* Found the command */
2974 2973 found = 1;
2975 2974 break;
2976 2975 }
2977 2976 if (!found) {
2978 2977 mutex_exit(&iport->iport_worker_lock);
2979 2978 rw_exit(&irp->irp_lock);
2980 2979 rw_exit(&iport->iport_lock);
2981 2980 /* Dont even bother queueing it. Just respond */
2982 2981 fct_fill_abts_acc(cmd);
2983 2982 if (port->port_send_cmd_response(cmd,
2984 2983 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2985 2984 /*
2986 2985 * XXX Throw HBA fatal error event
2987 2986 * Later shutdown svc will terminate the ABTS in the end
2988 2987 */
2989 2988 (void) snprintf(info, sizeof (info),
2990 2989 "fct_handle_rcvd_abts: iport-%p, "
2991 2990 "ABTS_ACC port_send_cmd_response failed",
2992 2991 (void *)iport);
2993 2992 (void) fct_port_shutdown(iport->iport_port,
2994 2993 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2995 2994 } else {
2996 2995 fct_cmd_free(cmd);
2997 2996 }
2998 2997 return;
2999 2998 }
3000 2999
3001 3000 /* Check if this an abts retry */
3002 3001 if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) {
3003 3002 /* Kill this abts. */
3004 3003 fct_q_for_termination_lock_held(iport, icmd, FCT_ABORTED);
3005 3004 if (IS_WORKER_SLEEPING(iport))
3006 3005 cv_signal(&iport->iport_worker_cv);
3007 3006 mutex_exit(&iport->iport_worker_lock);
3008 3007 rw_exit(&irp->irp_lock);
3009 3008 rw_exit(&iport->iport_lock);
3010 3009 return;
3011 3010 }
3012 3011 c->cmd_link = cmd;
3013 3012 atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED);
3014 3013 cmd->cmd_link = c;
3015 3014 mutex_exit(&iport->iport_worker_lock);
3016 3015 rw_exit(&irp->irp_lock);
3017 3016 fct_queue_cmd_for_termination(c, FCT_ABTS_RECEIVED);
3018 3017 rw_exit(&iport->iport_lock);
3019 3018 }
3020 3019
3021 3020 void
3022 3021 fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s)
3023 3022 {
3024 3023 fct_local_port_t *port = cmd->cmd_port;
3025 3024 fct_i_local_port_t *iport = (fct_i_local_port_t *)
3026 3025 port->port_fct_private;
3027 3026 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
3028 3027
3029 3028 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3030 3029 fct_queue_scsi_task_for_termination(cmd, s);
3031 3030 return;
3032 3031 }
3033 3032 mutex_enter(&iport->iport_worker_lock);
3034 3033 fct_q_for_termination_lock_held(iport, icmd, s);
3035 3034 if (IS_WORKER_SLEEPING(iport))
3036 3035 cv_signal(&iport->iport_worker_cv);
3037 3036 mutex_exit(&iport->iport_worker_lock);
3038 3037 }
3039 3038
3040 3039 /*
3041 3040 * This function will not be called for SCSI CMDS
3042 3041 */
3043 3042 void
3044 3043 fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
3045 3044 fct_status_t s)
3046 3045 {
3047 3046 uint32_t old, new;
3048 3047 fct_i_cmd_t **ppicmd;
3049 3048
3050 3049 do {
3051 3050 old = icmd->icmd_flags;
3052 3051 if (old & ICMD_BEING_ABORTED)
3053 3052 return;
3054 3053 new = old | ICMD_BEING_ABORTED;
3055 3054 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3056 3055
3057 3056 icmd->icmd_start_time = ddi_get_lbolt();
3058 3057 icmd->icmd_cmd->cmd_comp_status = s;
3059 3058
3060 3059 icmd->icmd_next = NULL;
3061 3060 for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
3062 3061 ppicmd = &((*ppicmd)->icmd_next))
3063 3062 ;
3064 3063
3065 3064 *ppicmd = icmd;
3066 3065 }
3067 3066
3068 3067 /*
3069 3068 * For those cmds, for which we called fca_abort but it has not yet completed,
3070 3069 * reset the FCA_ABORT_CALLED flag, so that abort can be called again.
3071 3070 * This is done after a FCA offline. The reason is that after offline, the
3072 3071 * firmware is not running so abort will never complete. But if we call it
3073 3072 * again, the FCA will detect that it is not offline and it will
3074 3073 * not call the firmware at all. Most likely it will abort in a synchronous
3075 3074 * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
3076 3075 */
3077 3076 void
3078 3077 fct_reset_flag_abort_called(fct_i_local_port_t *iport)
3079 3078 {
3080 3079 fct_i_cmd_t *icmd;
3081 3080 uint32_t old, new;
3082 3081 int i, do_clear;
3083 3082
3084 3083 ASSERT(mutex_owned(&iport->iport_worker_lock));
3085 3084 mutex_exit(&iport->iport_worker_lock);
3086 3085 rw_enter(&iport->iport_lock, RW_WRITER);
3087 3086 mutex_enter(&iport->iport_worker_lock);
3088 3087
3089 3088 for (i = 0; i < iport->iport_port->port_max_xchges; i++) {
3090 3089 if (iport->iport_cmd_slots[i].slot_cmd == NULL)
3091 3090 continue;
3092 3091
3093 3092 icmd = iport->iport_cmd_slots[i].slot_cmd;
3094 3093
3095 3094 do {
3096 3095 old = new = icmd->icmd_flags;
3097 3096 if ((old & (ICMD_KNOWN_TO_FCA |
3098 3097 ICMD_FCA_ABORT_CALLED)) == (ICMD_KNOWN_TO_FCA |
3099 3098 ICMD_FCA_ABORT_CALLED)) {
3100 3099 new &= ~ICMD_FCA_ABORT_CALLED;
3101 3100 do_clear = 1;
3102 3101 } else {
3103 3102 do_clear = 0;
3104 3103 break;
3105 3104 }
3106 3105 } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3107 3106 if (do_clear &&
3108 3107 (icmd->icmd_cmd->cmd_type == FCT_CMD_FCP_XCHG)) {
3109 3108 stmf_abort(STMF_REQUEUE_TASK_ABORT_LPORT,
3110 3109 icmd->icmd_cmd->cmd_specific, 0, NULL);
3111 3110 }
3112 3111 }
3113 3112
3114 3113 rw_exit(&iport->iport_lock);
3115 3114 }
3116 3115
3117 3116 /*
3118 3117 * Modify the irp_deregister_timer such that the ports start deregistering
3119 3118 * quickly.
3120 3119 */
3121 3120 void
3122 3121 fct_irp_deregister_speedup(fct_i_local_port_t *iport)
3123 3122 {
3124 3123 fct_i_remote_port_t *irp;
3125 3124 int i;
3126 3125
3127 3126 if (!iport->iport_nrps)
3128 3127 return;
3129 3128
3130 3129 for (i = 0; i < rportid_table_size; i++) {
3131 3130 irp = iport->iport_rp_tb[i];
3132 3131 while (irp) {
3133 3132 irp->irp_deregister_timer = ddi_get_lbolt() - 1;
3134 3133 irp = irp->irp_next;
3135 3134 }
3136 3135 }
3137 3136 }
3138 3137
3139 3138 disc_action_t
3140 3139 fct_handle_port_offline(fct_i_local_port_t *iport)
3141 3140 {
3142 3141 if (iport->iport_offline_prstate == FCT_OPR_START) {
3143 3142 fct_reset_flag_abort_called(iport);
3144 3143 iport->iport_offline_prstate = FCT_OPR_CMD_CLEANUP_WAIT;
3145 3144 /* fct_ctl has already submitted a link offline event */
3146 3145 return (DISC_ACTION_DELAY_RESCAN);
3147 3146 }
3148 3147 if (iport->iport_offline_prstate == FCT_OPR_CMD_CLEANUP_WAIT) {
3149 3148 if (iport->iport_link_state != PORT_STATE_LINK_DOWN)
3150 3149 return (DISC_ACTION_DELAY_RESCAN);
3151 3150 /*
3152 3151 * All I/Os have been killed at this time. Lets speedup
3153 3152 * the port deregister process.
3154 3153 */
3155 3154 mutex_exit(&iport->iport_worker_lock);
3156 3155 rw_enter(&iport->iport_lock, RW_WRITER);
3157 3156 fct_irp_deregister_speedup(iport);
3158 3157 rw_exit(&iport->iport_lock);
3159 3158 mutex_enter(&iport->iport_worker_lock);
3160 3159 iport->iport_offline_prstate = FCT_OPR_INT_CLEANUP_WAIT;
3161 3160 return (DISC_ACTION_RESCAN);
3162 3161 }
3163 3162 if (iport->iport_offline_prstate == FCT_OPR_INT_CLEANUP_WAIT) {
3164 3163 stmf_change_status_t st;
3165 3164
3166 3165 if (iport->iport_solcmd_queue) {
3167 3166 return (DISC_ACTION_DELAY_RESCAN);
3168 3167 }
3169 3168
3170 3169 if (iport->iport_nrps) {
3171 3170 /*
3172 3171 * A port logout may have gone when implicit logo all
3173 3172 * was retried. So do the port speedup again here.
3174 3173 */
3175 3174 mutex_exit(&iport->iport_worker_lock);
3176 3175 rw_enter(&iport->iport_lock, RW_WRITER);
3177 3176 fct_irp_deregister_speedup(iport);
3178 3177 rw_exit(&iport->iport_lock);
3179 3178 mutex_enter(&iport->iport_worker_lock);
3180 3179 return (DISC_ACTION_DELAY_RESCAN);
3181 3180 }
3182 3181
3183 3182 if (iport->iport_event_head != NULL) {
3184 3183 return (DISC_ACTION_DELAY_RESCAN);
3185 3184 }
3186 3185
3187 3186 st.st_completion_status = STMF_SUCCESS;
3188 3187 st.st_additional_info = NULL;
3189 3188 iport->iport_offline_prstate = FCT_OPR_DONE;
3190 3189 iport->iport_state = FCT_STATE_OFFLINE;
3191 3190 mutex_exit(&iport->iport_worker_lock);
3192 3191 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
3193 3192 iport->iport_port->port_lport, &st);
3194 3193 mutex_enter(&iport->iport_worker_lock);
3195 3194 return (DISC_ACTION_DELAY_RESCAN);
3196 3195 }
3197 3196
3198 3197 /* NOTREACHED */
3199 3198 return (0);
3200 3199 }
3201 3200
3202 3201 /*
3203 3202 * See stmf.h for information on rflags. Additional info is just a text
3204 3203 * description of the reason for this call. Additional_info can be NULL.
3205 3204 * Also the caller can declare additional info on the stack. stmf_ctl
3206 3205 * makes a copy of it before returning.
3207 3206 */
3208 3207 fct_status_t
3209 3208 fct_port_initialize(fct_local_port_t *port, uint32_t rflags,
3210 3209 char *additional_info)
3211 3210 {
3212 3211 stmf_state_change_info_t st;
3213 3212
3214 3213 st.st_rflags = rflags;
3215 3214 st.st_additional_info = additional_info;
3216 3215 stmf_trace(NULL, "fct_port_initialize: port-%p, %s", port,
3217 3216 additional_info? additional_info : "no more information");
3218 3217 return (stmf_ctl(STMF_CMD_LPORT_ONLINE, port->port_lport, &st));
3219 3218 }
3220 3219
3221 3220 fct_status_t
3222 3221 fct_port_shutdown(fct_local_port_t *port, uint32_t rflags,
3223 3222 char *additional_info)
3224 3223 {
3225 3224 stmf_state_change_info_t st;
3226 3225
3227 3226 st.st_rflags = rflags;
3228 3227 st.st_additional_info = additional_info;
3229 3228 stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port,
3230 3229 additional_info? additional_info : "no more information");
3231 3230 return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st));
3232 3231 }
3233 3232
3234 3233 /*
3235 3234 * Called by worker thread. The aim is to terminate the command
3236 3235 * using whatever means it takes.
3237 3236 * Called with worker lock held.
3238 3237 */
3239 3238 disc_action_t
3240 3239 fct_cmd_terminator(fct_i_local_port_t *iport)
3241 3240 {
3242 3241 char info[FCT_INFO_LEN];
3243 3242 clock_t endtime;
3244 3243 fct_i_cmd_t **ppicmd;
3245 3244 fct_i_cmd_t *icmd;
3246 3245 fct_cmd_t *cmd;
3247 3246 fct_local_port_t *port = iport->iport_port;
3248 3247 disc_action_t ret = DISC_ACTION_NO_WORK;
3249 3248 fct_status_t abort_ret;
3250 3249 int fca_done, fct_done, cmd_implicit = 0;
3251 3250 int flags;
3252 3251 unsigned long long st;
3253 3252
3254 3253 /* Lets Limit each run to 20ms max. */
3255 3254 endtime = ddi_get_lbolt() + drv_usectohz(20000);
3256 3255
3257 3256 /* Start from where we left off last time */
3258 3257 if (iport->iport_ppicmd_term) {
3259 3258 ppicmd = iport->iport_ppicmd_term;
3260 3259 iport->iport_ppicmd_term = NULL;
3261 3260 } else {
3262 3261 ppicmd = &iport->iport_abort_queue;
3263 3262 }
3264 3263
3265 3264 /*
3266 3265 * Once a command gets on discovery queue, this is the only thread
3267 3266 * which can access it. So no need for the lock here.
3268 3267 */
3269 3268 mutex_exit(&iport->iport_worker_lock);
3270 3269
3271 3270 while ((icmd = *ppicmd) != NULL) {
3272 3271 cmd = icmd->icmd_cmd;
3273 3272
3274 3273 /* Always remember that cmd->cmd_rp can be NULL */
3275 3274 if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA |
3276 3275 ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) {
3277 3276 atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3278 3277 if (CMD_HANDLE_VALID(cmd->cmd_handle))
3279 3278 flags = 0;
3280 3279 else
3281 3280 flags = FCT_IOF_FORCE_FCA_DONE;
3282 3281 abort_ret = port->port_abort_cmd(port, cmd, flags);
3283 3282 if ((abort_ret != FCT_SUCCESS) &&
3284 3283 (abort_ret != FCT_ABORT_SUCCESS) &&
3285 3284 (abort_ret != FCT_NOT_FOUND)) {
3286 3285 if (flags & FCT_IOF_FORCE_FCA_DONE) {
3287 3286 /*
3288 3287 * XXX trigger port fatal,
3289 3288 * Abort the termination, and shutdown
3290 3289 * svc will trigger fct_cmd_termination
3291 3290 * again.
3292 3291 */
3293 3292 (void) snprintf(info, sizeof (info),
3294 3293 "fct_cmd_terminator:"
3295 3294 " iport-%p, port_abort_cmd with "
3296 3295 "FORCE_FCA_DONE failed",
3297 3296 (void *)iport);
3298 3297 (void) fct_port_shutdown(
3299 3298 iport->iport_port,
3300 3299 STMF_RFLAG_FATAL_ERROR |
3301 3300 STMF_RFLAG_RESET, info);
3302 3301
3303 3302 mutex_enter(&iport->iport_worker_lock);
3304 3303 iport->iport_ppicmd_term = ppicmd;
3305 3304 return (DISC_ACTION_DELAY_RESCAN);
3306 3305 }
3307 3306 atomic_and_32(&icmd->icmd_flags,
3308 3307 ~ICMD_FCA_ABORT_CALLED);
3309 3308 } else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
3310 3309 (abort_ret == FCT_ABORT_SUCCESS) ||
3311 3310 (abort_ret == FCT_NOT_FOUND)) {
3312 3311 atomic_and_32(&icmd->icmd_flags,
3313 3312 ~ICMD_KNOWN_TO_FCA);
3314 3313 }
3315 3314 ret |= DISC_ACTION_DELAY_RESCAN;
3316 3315 } else if (icmd->icmd_flags & ICMD_IMPLICIT) {
3317 3316 if (cmd->cmd_type == FCT_CMD_SOL_ELS)
3318 3317 cmd->cmd_comp_status = FCT_ABORTED;
3319 3318 atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3320 3319 cmd_implicit = 1;
3321 3320 }
3322 3321 if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
3323 3322 fca_done = 1;
3324 3323 else
3325 3324 fca_done = 0;
3326 3325 if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0)
3327 3326 fct_done = 1;
3328 3327 else
3329 3328 fct_done = 0;
3330 3329 if ((fca_done || cmd_implicit) && fct_done) {
3331 3330 mutex_enter(&iport->iport_worker_lock);
3332 3331 ASSERT(*ppicmd == icmd);
3333 3332 *ppicmd = (*ppicmd)->icmd_next;
3334 3333 mutex_exit(&iport->iport_worker_lock);
3335 3334 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) ||
3336 3335 (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) {
3337 3336 /* Free the cmd */
3338 3337 fct_cmd_free(cmd);
3339 3338 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
3340 3339 fct_handle_sol_els_completion(iport, icmd);
3341 3340 if (icmd->icmd_flags & ICMD_IMPLICIT) {
3342 3341 if (IS_LOGO_ELS(icmd)) {
3343 3342 /* IMPLICIT LOGO is special */
3344 3343 fct_cmd_free(cmd);
3345 3344 }
3346 3345 }
3347 3346 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3348 3347 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
3349 3348
3350 3349 /* Tell the caller that we are done */
3351 3350 atomic_or_32(&icmd->icmd_flags,
3352 3351 ICMD_CMD_COMPLETE);
3353 3352 if (fct_netbuf_to_value(
3354 3353 ct->ct_req_payload + 8, 2) == NS_GID_PN) {
3355 3354 fct_i_remote_port_t *irp;
3356 3355
3357 3356 rw_enter(&iport->iport_lock, RW_READER);
3358 3357 irp = fct_lookup_irp_by_portwwn(iport,
3359 3358 ct->ct_req_payload + 16);
3360 3359
3361 3360 if (irp) {
3362 3361 atomic_and_32(&irp->irp_flags,
3363 3362 ~IRP_RSCN_QUEUED);
3364 3363 }
3365 3364 rw_exit(&iport->iport_lock);
3366 3365 }
3367 3366 } else {
3368 3367 ASSERT(0);
3369 3368 }
3370 3369 } else {
3371 3370 clock_t timeout_ticks;
3372 3371 if (port->port_fca_abort_timeout)
3373 3372 timeout_ticks = drv_usectohz(
3374 3373 port->port_fca_abort_timeout*1000);
3375 3374 else
3376 3375 /* 10 seconds by default */
3377 3376 timeout_ticks = drv_usectohz(10 * 1000000);
3378 3377 if ((ddi_get_lbolt() >
3379 3378 (icmd->icmd_start_time+timeout_ticks)) &&
3380 3379 iport->iport_state == FCT_STATE_ONLINE) {
3381 3380 /* timeout, reset the port */
3382 3381 char cmd_type[10];
3383 3382 if (cmd->cmd_type == FCT_CMD_RCVD_ELS ||
3384 3383 cmd->cmd_type == FCT_CMD_SOL_ELS) {
3385 3384 fct_els_t *els = cmd->cmd_specific;
3386 3385 (void) snprintf(cmd_type,
3387 3386 sizeof (cmd_type), "%x.%x",
3388 3387 cmd->cmd_type,
3389 3388 els->els_req_payload[0]);
3390 3389 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3391 3390 fct_sol_ct_t *ct = cmd->cmd_specific;
3392 3391 (void) snprintf(cmd_type,
3393 3392 sizeof (cmd_type), "%x.%02x%02x",
3394 3393 cmd->cmd_type,
3395 3394 ct->ct_req_payload[8],
3396 3395 ct->ct_req_payload[9]);
3397 3396 } else {
3398 3397 cmd_type[0] = 0;
3399 3398 }
3400 3399 st = cmd->cmd_comp_status; /* gcc fix */
3401 3400 (void) snprintf(info, sizeof (info),
3402 3401 "fct_cmd_terminator:"
3403 3402 " iport-%p, cmd_type(0x%s),"
3404 3403 " reason(%llx)", (void *)iport, cmd_type,
3405 3404 st);
3406 3405 (void) fct_port_shutdown(port,
3407 3406 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET,
3408 3407 info);
3409 3408 }
3410 3409 ppicmd = &((*ppicmd)->icmd_next);
3411 3410 }
3412 3411
3413 3412 if (ddi_get_lbolt() > endtime) {
3414 3413 mutex_enter(&iport->iport_worker_lock);
3415 3414 iport->iport_ppicmd_term = ppicmd;
3416 3415 return (DISC_ACTION_DELAY_RESCAN);
3417 3416 }
3418 3417 }
3419 3418 mutex_enter(&iport->iport_worker_lock);
3420 3419 if (iport->iport_abort_queue)
3421 3420 return (DISC_ACTION_DELAY_RESCAN);
3422 3421 if (ret == DISC_ACTION_NO_WORK)
3423 3422 return (DISC_ACTION_RESCAN);
3424 3423 return (ret);
3425 3424 }
3426 3425
3427 3426 /*
3428 3427 * Send a syslog event for adapter port level events.
3429 3428 */
3430 3429 void
3431 3430 fct_log_local_port_event(fct_local_port_t *port, char *subclass)
3432 3431 {
3433 3432 nvlist_t *attr_list;
3434 3433 int port_instance;
3435 3434
3436 3435 if (!fct_dip)
3437 3436 return;
3438 3437 port_instance = ddi_get_instance(fct_dip);
3439 3438
3440 3439 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3441 3440 KM_SLEEP) != DDI_SUCCESS) {
3442 3441 goto alloc_failed;
3443 3442 }
3444 3443
3445 3444 if (nvlist_add_uint32(attr_list, "instance", port_instance)
3446 3445 != DDI_SUCCESS) {
3447 3446 goto error;
3448 3447 }
3449 3448
3450 3449 if (nvlist_add_byte_array(attr_list, "port-wwn",
3451 3450 port->port_pwwn, 8) != DDI_SUCCESS) {
3452 3451 goto error;
3453 3452 }
3454 3453
3455 3454 (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3456 3455 subclass, attr_list, NULL, DDI_SLEEP);
3457 3456
3458 3457 nvlist_free(attr_list);
3459 3458 return;
3460 3459
3461 3460 error:
3462 3461 nvlist_free(attr_list);
3463 3462 alloc_failed:
3464 3463 stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3465 3464 "Unable to send %s event", subclass);
3466 3465 }
3467 3466
3468 3467 void
3469 3468 fct_log_remote_port_event(fct_local_port_t *port, char *subclass,
3470 3469 uint8_t *rp_pwwn, uint32_t rp_id)
3471 3470 {
3472 3471 nvlist_t *attr_list;
3473 3472 int port_instance;
3474 3473
3475 3474 if (!fct_dip)
3476 3475 return;
3477 3476 port_instance = ddi_get_instance(fct_dip);
3478 3477
3479 3478 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3480 3479 KM_SLEEP) != DDI_SUCCESS) {
3481 3480 goto alloc_failed;
3482 3481 }
3483 3482
3484 3483 if (nvlist_add_uint32(attr_list, "instance", port_instance)
3485 3484 != DDI_SUCCESS) {
3486 3485 goto error;
3487 3486 }
3488 3487
3489 3488 if (nvlist_add_byte_array(attr_list, "port-wwn",
3490 3489 port->port_pwwn, 8) != DDI_SUCCESS) {
3491 3490 goto error;
3492 3491 }
3493 3492
3494 3493 if (nvlist_add_byte_array(attr_list, "target-port-wwn",
3495 3494 rp_pwwn, 8) != DDI_SUCCESS) {
3496 3495 goto error;
3497 3496 }
3498 3497
3499 3498 if (nvlist_add_uint32(attr_list, "target-port-id",
3500 3499 rp_id) != DDI_SUCCESS) {
3501 3500 goto error;
3502 3501 }
3503 3502
3504 3503 (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3505 3504 subclass, attr_list, NULL, DDI_SLEEP);
3506 3505
3507 3506 nvlist_free(attr_list);
3508 3507 return;
3509 3508
3510 3509 error:
3511 3510 nvlist_free(attr_list);
3512 3511 alloc_failed:
3513 3512 stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3514 3513 "Unable to send %s event", subclass);
3515 3514 }
3516 3515
3517 3516 uint64_t
3518 3517 fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes)
3519 3518 {
3520 3519 uint64_t ret = 0;
3521 3520 uint8_t idx = 0;
3522 3521
3523 3522 do {
3524 3523 ret |= (buf[idx] << (8 * (nbytes -idx - 1)));
3525 3524 } while (++idx < nbytes);
3526 3525
3527 3526 return (ret);
3528 3527 }
3529 3528
3530 3529 void
3531 3530 fct_value_to_netbuf(uint64_t value, uint8_t *buf, uint8_t nbytes)
3532 3531 {
3533 3532 uint8_t idx = 0;
3534 3533
3535 3534 for (idx = 0; idx < nbytes; idx++) {
3536 3535 buf[idx] = 0xFF & (value >> (8 * (nbytes - idx - 1)));
3537 3536 }
3538 3537 }
3539 3538
3540 3539 /*
3541 3540 * from_ptr: ptr to uchar_t array of size WWN_SIZE
3542 3541 * to_ptr: char ptr to string of size WWN_SIZE*2+1
3543 3542 */
3544 3543 void
3545 3544 fct_wwn_to_str(char *to_ptr, const uint8_t *from_ptr)
3546 3545 {
3547 3546 ASSERT(to_ptr != NULL && from_ptr != NULL);
3548 3547
3549 3548 (void) sprintf(to_ptr, "%02x%02x%02x%02x%02x%02x%02x%02x",
3550 3549 from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
3551 3550 from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
3552 3551 }
3553 3552
3554 3553 static int
3555 3554 fct_update_stats(kstat_t *ks, int rw)
3556 3555 {
3557 3556 fct_i_local_port_t *iport;
3558 3557 fct_port_stat_t *port_kstat;
3559 3558 fct_port_link_status_t stat;
3560 3559 uint32_t buf_size = sizeof (stat);
3561 3560 int ret;
3562 3561
3563 3562 if (rw == KSTAT_WRITE)
3564 3563 return (EACCES);
3565 3564
3566 3565 iport = (fct_i_local_port_t *)ks->ks_private;
3567 3566 port_kstat = (fct_port_stat_t *)ks->ks_data;
3568 3567
3569 3568 if (iport->iport_port->port_info == NULL) {
3570 3569 return (EIO);
3571 3570 }
3572 3571 ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
3573 3572 iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
3574 3573 if (ret != STMF_SUCCESS) {
3575 3574 return (EIO);
3576 3575 }
3577 3576
3578 3577 port_kstat->link_failure_cnt.value.ui32 =
3579 3578 stat.LinkFailureCount;
3580 3579 port_kstat->loss_of_sync_cnt.value.ui32 =
3581 3580 stat.LossOfSyncCount;
3582 3581 port_kstat->loss_of_signals_cnt.value.ui32 =
3583 3582 stat.LossOfSignalsCount;
3584 3583 port_kstat->prim_seq_protocol_err_cnt.value.ui32 =
3585 3584 stat.PrimitiveSeqProtocolErrorCount;
3586 3585 port_kstat->invalid_tx_word_cnt.value.ui32 =
3587 3586 stat.InvalidTransmissionWordCount;
3588 3587 port_kstat->invalid_crc_cnt.value.ui32 =
3589 3588 stat.InvalidCRCCount;
3590 3589
3591 3590 return (0);
3592 3591 }
3593 3592
3594 3593 void
3595 3594 fct_init_kstats(fct_i_local_port_t *iport)
3596 3595 {
3597 3596 kstat_t *ks;
3598 3597 fct_port_stat_t *port_kstat;
3599 3598 char name[256];
3600 3599
3601 3600 if (iport->iport_alias)
3602 3601 (void) sprintf(name, "iport_%s", iport->iport_alias);
3603 3602 else
3604 3603 (void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport);
3605 3604 ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata",
3606 3605 KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t),
3607 3606 0);
3608 3607
3609 3608 if (ks == NULL) {
3610 3609 return;
3611 3610 }
3612 3611 port_kstat = (fct_port_stat_t *)ks->ks_data;
3613 3612
3614 3613 iport->iport_kstat_portstat = ks;
3615 3614 kstat_named_init(&port_kstat->link_failure_cnt,
3616 3615 "Link_failure_cnt", KSTAT_DATA_UINT32);
3617 3616 kstat_named_init(&port_kstat->loss_of_sync_cnt,
3618 3617 "Loss_of_sync_cnt", KSTAT_DATA_UINT32);
3619 3618 kstat_named_init(&port_kstat->loss_of_signals_cnt,
3620 3619 "Loss_of_signals_cnt", KSTAT_DATA_UINT32);
3621 3620 kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt,
3622 3621 "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32);
3623 3622 kstat_named_init(&port_kstat->invalid_tx_word_cnt,
3624 3623 "Invalid_tx_word_cnt", KSTAT_DATA_UINT32);
3625 3624 kstat_named_init(&port_kstat->invalid_crc_cnt,
3626 3625 "Invalid_crc_cnt", KSTAT_DATA_UINT32);
3627 3626 ks->ks_update = fct_update_stats;
3628 3627 ks->ks_private = (void *)iport;
3629 3628 kstat_install(ks);
3630 3629
3631 3630 }
↓ open down ↓ |
3513 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX