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