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