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