Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c
+++ new/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.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 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 #include <sys/conf.h>
27 27 #include <sys/ddi.h>
28 28 #include <sys/stat.h>
29 29 #include <sys/pci.h>
30 30 #include <sys/sunddi.h>
31 31 #include <sys/modctl.h>
32 32 #include <sys/file.h>
33 33 #include <sys/cred.h>
34 34 #include <sys/byteorder.h>
35 35 #include <sys/atomic.h>
36 36 #include <sys/scsi/scsi.h>
37 37 #include <sys/mac_client.h>
38 38 #include <sys/modhash.h>
39 39
40 40 /*
41 41 * leadville header files
42 42 */
43 43 #include <sys/fibre-channel/fc.h>
44 44 #include <sys/fibre-channel/impl/fc_fcaif.h>
45 45
46 46 /*
47 47 * fcoe header files
48 48 */
49 49 #include <sys/fcoe/fcoe_common.h>
50 50
51 51 /*
52 52 * fcoei header files
53 53 */
54 54 #include <fcoei.h>
55 55
56 56 /*
57 57 * forward declaration of stack functions
58 58 */
59 59 static uint32_t fcoei_xch_check(
60 60 mod_hash_key_t key, mod_hash_val_t *val, void *arg);
61 61 static int fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
62 62 static int fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
63 63 static int fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp);
64 64 static int fcoei_close(dev_t dev, int flag, int otype, cred_t *credp);
65 65 static int fcoei_ioctl(
66 66 dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval);
67 67 static int fcoei_attach_init(fcoei_soft_state_t *ss);
68 68 static int fcoei_detach_uninit(fcoei_soft_state_t *ss);
69 69 static void fcoei_watchdog(void *arg);
70 70 static void fcoei_process_events(fcoei_soft_state_t *ss);
71 71 static void fcoei_trigger_fp_attach(void *arg);
72 72 static void fcoei_abts_exchange(fcoei_exchange_t *xch);
73 73 static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss);
74 74
75 75 /*
76 76 * Driver identificaton stuff
77 77 */
78 78 static struct cb_ops fcoei_cb_ops = {
79 79 fcoei_open,
80 80 fcoei_close,
81 81 nodev,
82 82 nodev,
83 83 nodev,
84 84 nodev,
85 85 nodev,
86 86 fcoei_ioctl,
87 87 nodev,
88 88 nodev,
89 89 nodev,
90 90 nochpoll,
91 91 ddi_prop_op,
92 92 0,
93 93 D_MP | D_NEW | D_HOTPLUG,
94 94 CB_REV,
95 95 nodev,
96 96 nodev
97 97 };
98 98
99 99 static struct dev_ops fcoei_ops = {
100 100 DEVO_REV,
101 101 0,
102 102 nodev,
103 103 nulldev,
104 104 nulldev,
105 105 fcoei_attach,
106 106 fcoei_detach,
107 107 nodev,
108 108 &fcoei_cb_ops,
109 109 NULL,
110 110 ddi_power,
111 111 ddi_quiesce_not_needed
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
112 112 };
113 113
114 114 static struct modldrv modldrv = {
115 115 &mod_driverops,
116 116 FCOEI_NAME_VERSION,
117 117 &fcoei_ops,
118 118 };
119 119
120 120 static struct modlinkage modlinkage = {
121 121 MODREV_1,
122 - &modldrv,
123 - NULL
122 + { &modldrv, NULL }
124 123 };
125 124
126 125 /*
127 126 * Driver's global variables
128 127 */
129 128 void *fcoei_state = NULL;
130 129 int fcoei_use_ext_log = 0;
131 130
132 131 /*
133 132 * Common loadable module entry points _init, _fini, _info
134 133 */
135 134 int
136 135 _init(void)
137 136 {
138 137 int ret;
139 138
140 139 ret = ddi_soft_state_init(&fcoei_state, sizeof (fcoei_soft_state_t), 0);
141 140 if (ret != DDI_SUCCESS) {
142 141 FCOEI_LOG(__FUNCTION__, "soft state init failed: %x", ret);
143 142 return (ret);
144 143 }
145 144
146 145 ret = mod_install(&modlinkage);
147 146 if (ret != 0) {
148 147 ddi_soft_state_fini(&fcoei_state);
149 148 FCOEI_LOG(__FUNCTION__, "fcoei mod_install failed: %x", ret);
150 149 return (ret);
151 150 }
152 151
153 152 /*
154 153 * Let FCTL initialize devo_bus_ops
155 154 */
156 155 fc_fca_init(&fcoei_ops);
157 156
158 157 FCOEI_LOG(__FUNCTION__, "fcoei _init succeeded");
159 158 return (ret);
160 159 }
161 160
162 161 int
163 162 _fini(void)
164 163 {
165 164 int ret;
166 165
167 166 ret = mod_remove(&modlinkage);
168 167 if (ret != 0) {
169 168 FCOEI_EXT_LOG(__FUNCTION__, "fcoei mod_remove failed: %x", ret);
170 169 return (ret);
171 170 }
172 171
173 172 ddi_soft_state_fini(&fcoei_state);
174 173 FCOEI_LOG(__FUNCTION__, "fcoei _fini succeeded");
175 174 return (ret);
176 175 }
177 176
178 177 int
179 178 _info(struct modinfo *modinfop)
180 179 {
181 180 return (mod_info(&modlinkage, modinfop));
182 181 }
183 182
184 183 /*
185 184 * Autoconfiguration entry points: attach, detach, getinfo
186 185 */
187 186
188 187 static int
189 188 fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
190 189 {
191 190 int ret;
192 191 int fcoe_ret;
193 192 int instance;
194 193 fcoei_soft_state_t *ss;
195 194
196 195 instance = ddi_get_instance(dip);
197 196 FCOEI_LOG(__FUNCTION__, "instance is %d", instance);
198 197 switch (cmd) {
199 198 case DDI_ATTACH:
200 199 ret = ddi_soft_state_zalloc(fcoei_state, instance);
201 200 if (ret != DDI_SUCCESS) {
202 201 FCOEI_LOG(__FUNCTION__, "ss zalloc failed: %x", ret);
203 202 return (ret);
204 203 }
205 204
206 205 /*
207 206 * Get the soft state, and do basic initialization with dip
208 207 */
209 208 ss = ddi_get_soft_state(fcoei_state, instance);
210 209 ss->ss_dip = dip;
211 210
212 211 fcoe_ret = fcoei_attach_init(ss);
213 212 if (fcoe_ret != FCOE_SUCCESS) {
214 213 ddi_soft_state_free(fcoei_state, instance);
215 214 FCOEI_LOG(__FUNCTION__, "fcoei_attach_init failed: "
216 215 "%x", fcoe_ret);
217 216 return (DDI_FAILURE);
218 217 }
219 218
220 219 ss->ss_flags |= SS_FLAG_TRIGGER_FP_ATTACH;
221 220 (void) timeout(fcoei_trigger_fp_attach, ss, FCOE_SEC2TICK(1));
222 221 FCOEI_LOG(__FUNCTION__, "fcoei_attach succeeded: dip-%p, "
223 222 "cmd-%x", dip, cmd);
224 223 return (DDI_SUCCESS);
225 224
226 225 case DDI_RESUME:
227 226 return (DDI_SUCCESS);
228 227
229 228 default:
230 229 FCOEI_LOG(__FUNCTION__, "unsupported attach cmd-%X", cmd);
231 230 return (DDI_FAILURE);
232 231 }
233 232 }
234 233
235 234 static int
236 235 fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
237 236 {
238 237 int fcoe_ret;
239 238 int instance;
240 239 fcoei_soft_state_t *ss;
241 240
242 241 instance = ddi_get_instance(dip);
243 242 ss = ddi_get_soft_state(fcoei_state, instance);
244 243 if (ss == NULL) {
245 244 FCOEI_LOG(__FUNCTION__, "get ss failed: dip-%p", dip);
246 245 return (DDI_FAILURE);
247 246 }
248 247
249 248 switch (cmd) {
250 249 case DDI_DETACH:
251 250 if (ss->ss_flags & SS_FLAG_TRIGGER_FP_ATTACH) {
252 251 FCOEI_LOG(__FUNCTION__, "still await fp attach");
253 252 return (DDI_FAILURE);
254 253 }
255 254
256 255 if (ss->ss_flags & SS_FLAG_LV_BOUND) {
257 256 FCOEI_LOG(__FUNCTION__, "fp is not detached yet");
258 257 return (DDI_FAILURE);
259 258 }
260 259
261 260 fcoe_ret = fcoei_detach_uninit(ss);
262 261 if (fcoe_ret != FCOE_SUCCESS) {
263 262 FCOEI_LOG(__FUNCTION__, "fcoei_detach_uninit failed:"
264 263 " dip-%p, fcoe_ret-%d", dip, fcoe_ret);
265 264 return (DDI_FAILURE);
266 265 }
267 266
268 267 FCOEI_LOG(__FUNCTION__, "succeeded: dip-%p, cmd-%x", dip, cmd);
269 268 return (DDI_SUCCESS);
270 269
271 270 case DDI_SUSPEND:
272 271 return (DDI_SUCCESS);
273 272
274 273 default:
275 274 FCOEI_LOG(__FUNCTION__, "unspported detach cmd-%X", cmd);
276 275 return (DDI_FAILURE);
277 276 }
278 277 }
279 278
280 279 /*
281 280 * Device access entry points: open, close, ioctl
282 281 */
283 282
284 283 static int
285 284 fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp)
286 285 {
287 286 fcoei_soft_state_t *ss;
288 287
289 288 if (otype != OTYP_CHR) {
290 289 FCOEI_LOG(__FUNCTION__, "flag: %x", flag);
291 290 return (EINVAL);
292 291 }
293 292
294 293 if (drv_priv(credp)) {
295 294 return (EPERM);
296 295 }
297 296
298 297 /*
299 298 * First of all, get related soft state
300 299 */
301 300 ss = ddi_get_soft_state(fcoei_state, (int)getminor(*devp));
302 301 if (ss == NULL) {
303 302 return (ENXIO);
304 303 }
305 304
306 305 mutex_enter(&ss->ss_ioctl_mutex);
307 306 if (ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN) {
308 307 /*
309 308 * We don't support concurrent open
310 309 */
311 310 mutex_exit(&ss->ss_ioctl_mutex);
312 311 return (EBUSY);
313 312 }
314 313
315 314 ss->ss_ioctl_flags |= FCOEI_IOCTL_FLAG_OPEN;
316 315 mutex_exit(&ss->ss_ioctl_mutex);
317 316
318 317 return (0);
319 318 }
320 319
321 320 static int
322 321 fcoei_close(dev_t dev, int flag, int otype, cred_t *credp)
323 322 {
324 323 fcoei_soft_state_t *ss;
325 324
326 325 if (otype != OTYP_CHR) {
327 326 FCOEI_LOG(__FUNCTION__, "flag: %x, %p", flag, credp);
328 327 return (EINVAL);
329 328 }
330 329
331 330 /*
332 331 * First of all, get related soft state
333 332 */
334 333 ss = ddi_get_soft_state(fcoei_state, (int)getminor(dev));
335 334 if (ss == NULL) {
336 335 return (ENXIO);
337 336 }
338 337
339 338 mutex_enter(&ss->ss_ioctl_mutex);
340 339 if (!(ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN)) {
341 340 /*
342 341 * If it's not open, we can exit
343 342 */
344 343
345 344 mutex_exit(&ss->ss_ioctl_mutex);
346 345 return (ENODEV);
347 346 }
348 347
349 348 ss->ss_ioctl_flags &= ~FCOEI_IOCTL_FLAG_OPEN;
350 349 mutex_exit(&ss->ss_ioctl_mutex);
351 350
352 351 return (0);
353 352 }
354 353
355 354 static int
356 355 fcoei_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
357 356 cred_t *credp, int *rval)
358 357 {
359 358 fcoei_soft_state_t *ss;
360 359 int ret = 0;
361 360
362 361 if (drv_priv(credp) != 0) {
363 362 FCOEI_LOG(__FUNCTION__, "data: %p, %x", data, mode);
364 363 return (EPERM);
365 364 }
366 365
367 366 /*
368 367 * Get related soft state
369 368 */
370 369 ss = ddi_get_soft_state(fcoei_state, (int32_t)getminor(dev));
371 370 if (!ss) {
372 371 return (ENXIO);
373 372 }
374 373
375 374 /*
376 375 * Process ioctl
377 376 */
378 377 switch (cmd) {
379 378
380 379 default:
381 380 FCOEI_LOG(__FUNCTION__, "ioctl-0x%02X", cmd);
382 381 ret = ENOTTY;
383 382 }
384 383
385 384 /*
386 385 * Set return value
387 386 */
388 387 *rval = ret;
389 388 return (ret);
390 389 }
391 390
392 391 /*
393 392 * fcoei_attach_init
394 393 * init related stuff of the soft state
395 394 *
396 395 * Input:
397 396 * ss = the soft state that will be processed
398 397 *
399 398 * Return:
400 399 * if it succeeded or not
401 400 *
402 401 * Comment:
403 402 * N/A
404 403 */
405 404 static int
406 405 fcoei_attach_init(fcoei_soft_state_t *ss)
407 406 {
408 407 fcoe_port_t *eport;
409 408 fcoe_client_t client_fcoei;
410 409 char taskq_name[32];
411 410 int ret;
412 411 la_els_logi_t *els = &ss->ss_els_logi;
413 412 svc_param_t *class3_param;
414 413
415 414 /*
416 415 * Register fcoei to FCOE as its client
417 416 */
418 417 client_fcoei.ect_eport_flags = EPORT_FLAG_INI_MODE |
419 418 EPORT_FLAG_IS_DIRECT_P2P;
420 419 client_fcoei.ect_max_fc_frame_size = FCOE_MAX_FC_FRAME_SIZE;
421 420 client_fcoei.ect_private_frame_struct_size = sizeof (fcoei_frame_t);
422 421 fcoei_init_ect_vectors(&client_fcoei);
423 422 client_fcoei.ect_client_port_struct = ss;
424 423 client_fcoei.ect_fcoe_ver = FCOE_VER_NOW;
425 424 FCOEI_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
426 425 ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
427 426 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
428 427 if (ret == -1) {
429 428 FCOEI_LOG(__FUNCTION__, "get mac_id failed");
430 429 return (DDI_FAILURE);
431 430 } else {
432 431 client_fcoei.ect_channelid = ret;
433 432 }
434 433
435 434 /*
436 435 * It's fcoe's responsiblity to initialize eport's all elements,
437 436 * so we needn't do eport initialization
438 437 */
439 438 eport = fcoe_register_client(&client_fcoei);
440 439 if (eport == NULL) {
441 440 goto fail_register_client;
442 441 } else {
443 442 ss->ss_eport = eport;
444 443 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
445 444 }
446 445
447 446 /*
448 447 * Now it's time to register fca_tran to FCTL
449 448 * Remember fc_local_port is transparent to FCA (fcoei)
450 449 */
451 450 ss->ss_fca_tran.fca_version = FCTL_FCA_MODREV_5;
452 451 ss->ss_fca_tran.fca_numports = 1;
453 452 ss->ss_fca_tran.fca_pkt_size = sizeof (fcoei_exchange_t);
454 453 ss->ss_fca_tran.fca_cmd_max = 2048;
455 454
456 455 /*
457 456 * scsi_tran_hba_setup could need these stuff
458 457 */
459 458 ss->ss_fca_tran.fca_dma_lim = NULL;
460 459 ss->ss_fca_tran.fca_iblock = NULL;
461 460 ss->ss_fca_tran.fca_dma_attr = NULL;
462 461 ss->ss_fca_tran.fca_acc_attr = NULL;
463 462
464 463 /*
465 464 * Initialize vectors
466 465 */
467 466 fcoei_init_fcatran_vectors(&ss->ss_fca_tran);
468 467
469 468 /*
470 469 * fc_fca_attach only sets driver's private, it has nothing to with
471 470 * common port object between fcoei and leadville.
472 471 * After this attach, fp_attach will be triggered, and it will call
473 472 * fca_bind_port to let fcoei to know about common port object.
474 473 */
475 474 if (fc_fca_attach(ss->ss_dip, &ss->ss_fca_tran) != DDI_SUCCESS) {
476 475 goto fail_fca_attach;
477 476 }
478 477
479 478 /*
480 479 * It's time to do ss initialization
481 480 */
482 481 ret = ddi_create_minor_node(ss->ss_dip, "admin",
483 482 S_IFCHR, ddi_get_instance(ss->ss_dip), DDI_NT_NEXUS, 0);
484 483 if (ret != DDI_SUCCESS) {
485 484 goto fail_minor_node;
486 485 }
487 486
488 487 ss->ss_flags = 0;
489 488 ss->ss_port = NULL;
490 489 /*
491 490 * ss->ss_eport has been initialized
492 491 */
493 492
494 493 ss->ss_sol_oxid_hash = mod_hash_create_idhash(
495 494 "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE,
496 495 mod_hash_null_valdtor);
497 496 ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
498 497 "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE,
499 498 mod_hash_null_valdtor);
500 499 list_create(&ss->ss_comp_xch_list, sizeof (fcoei_exchange_t),
501 500 offsetof(fcoei_exchange_t, xch_comp_node));
502 501 ss->ss_next_sol_oxid = 0xFFFF;
503 502 ss->ss_next_unsol_rxid = 0xFFFF;
504 503
505 504 mutex_init(&ss->ss_watchdog_mutex, 0, MUTEX_DRIVER, 0);
506 505 cv_init(&ss->ss_watchdog_cv, NULL, CV_DRIVER, NULL);
507 506 (void) snprintf(taskq_name, 32, "leadville_fcoei_%d_taskq",
508 507 ddi_get_instance(ss->ss_dip));
509 508 taskq_name[31] = 0;
510 509 ss->ss_taskq = ddi_taskq_create(ss->ss_dip,
511 510 taskq_name, 64, TASKQ_DEFAULTPRI, DDI_SLEEP);
512 511
513 512 ss->ss_link_state = FC_STATE_OFFLINE;
514 513 ss->ss_link_speed = 0;
515 514 ss->ss_port_event_counter = 0;
516 515
517 516 list_create(&ss->ss_event_list, sizeof (fcoei_event_t),
518 517 offsetof(fcoei_event_t, ae_node));
519 518
520 519 ss->ss_sol_cnt1 = 0;
521 520 ss->ss_sol_cnt2 = 0;
522 521 ss->ss_sol_cnt = &ss->ss_sol_cnt1;
523 522 ss->ss_unsol_cnt1 = 0;
524 523 ss->ss_unsol_cnt2 = 0;
525 524 ss->ss_unsol_cnt = &ss->ss_unsol_cnt1;
526 525 ss->ss_ioctl_flags = 0;
527 526
528 527 mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
529 528
530 529 bcopy(eport->eport_portwwn, els->nport_ww_name.raw_wwn, 8);
531 530 bcopy(eport->eport_nodewwn, els->node_ww_name.raw_wwn, 8);
532 531 els->common_service.fcph_version = 0x2008;
533 532 els->common_service.btob_credit = 3;
534 533 els->common_service.cmn_features = 0x8800;
535 534 els->common_service.conc_sequences = 0xff;
536 535 els->common_service.relative_offset = 3;
537 536 els->common_service.e_d_tov = 0x07d0;
538 537 class3_param = (svc_param_t *)&els->class_3;
539 538 class3_param->class_opt = 0x8800;
540 539 class3_param->rcv_size = els->common_service.rx_bufsize = 2048;
541 540 class3_param->conc_sequences = 0xff;
542 541 class3_param->open_seq_per_xchng = 1;
543 542
544 543 /*
545 544 * Fill out RNID Management Information
546 545 */
547 546 bcopy(ss->ss_eport->eport_portwwn, ss->ss_rnid.global_id, 8);
548 547 ss->ss_rnid.unit_type = FCOEI_RNID_HBA;
549 548 ss->ss_rnid.ip_version = FCOEI_RNID_IPV4;
550 549
551 550 /*
552 551 * Start our watchdog
553 552 */
554 553 (void) ddi_taskq_dispatch(ss->ss_taskq,
555 554 fcoei_watchdog, ss, DDI_SLEEP);
556 555 while (!(ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING)) {
557 556 delay(50);
558 557 }
559 558
560 559 /*
561 560 * Report the device to the system
562 561 */
563 562 ddi_report_dev(ss->ss_dip);
564 563 return (DDI_SUCCESS);
565 564
566 565
567 566 fail_minor_node:
568 567 FCOEI_LOG(__FUNCTION__, "fail_minor_node");
569 568 (void) fc_fca_detach(ss->ss_dip);
570 569
571 570 fail_fca_attach:
572 571 eport->eport_deregister_client(eport);
573 572 FCOEI_LOG(__FUNCTION__, "fail_fca_attach");
574 573
575 574 fail_register_client:
576 575 FCOEI_LOG(__FUNCTION__, "fail_register_client");
577 576 return (DDI_FAILURE);
578 577 }
579 578
580 579 /*
581 580 * fcoei_detach_uninit
582 581 * uninit related stuff of the soft state
583 582 *
584 583 * Input:
585 584 * ss = the soft state that will be processed
586 585 *
587 586 * Return:
588 587 * if it succeeded or not
589 588 *
590 589 * Comment:
591 590 * N/A
592 591 */
593 592 int
594 593 fcoei_detach_uninit(fcoei_soft_state_t *ss)
595 594 {
596 595 /*
597 596 * Stop watchdog first
598 597 */
599 598 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
600 599 ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
601 600 cv_broadcast(&ss->ss_watchdog_cv);
602 601 }
603 602
604 603 /*
605 604 * Destroy the taskq
606 605 */
607 606 ddi_taskq_wait(ss->ss_taskq);
608 607 ddi_taskq_destroy(ss->ss_taskq);
609 608
610 609 /*
611 610 * Release all allocated resources
612 611 */
613 612 mutex_destroy(&ss->ss_ioctl_mutex);
614 613 mutex_destroy(&ss->ss_watchdog_mutex);
615 614 cv_destroy(&ss->ss_watchdog_cv);
616 615 mod_hash_destroy_idhash(ss->ss_sol_oxid_hash);
617 616 mod_hash_destroy_idhash(ss->ss_unsol_rxid_hash);
618 617 list_destroy(&ss->ss_event_list);
619 618 ss->ss_eport->eport_deregister_client(ss->ss_eport);
620 619 ddi_remove_minor_node(ss->ss_dip, NULL);
621 620
622 621 /*
623 622 * Release itself
624 623 */
625 624 ddi_soft_state_free(fcoei_state, ddi_get_instance(ss->ss_dip));
626 625 return (FCOE_SUCCESS);
627 626 }
628 627
629 628 /*
630 629 * fcoei_watchdog
631 630 * Perform periodic checking and routine tasks
632 631 *
633 632 * Input:
634 633 * arg = the soft state that will be processed
635 634 *
636 635 * Return:
637 636 * N/A
638 637 *
639 638 * Comment:
640 639 * N/A
641 640 */
642 641 static void
643 642 fcoei_watchdog(void *arg)
644 643 {
645 644 fcoei_soft_state_t *ss;
646 645 clock_t tmp_delay;
647 646 clock_t start_clock;
648 647 clock_t last_clock;
649 648
650 649 /*
651 650 * For debugging
652 651 */
653 652 ss = (fcoei_soft_state_t *)arg;
654 653 FCOEI_LOG(__FUNCTION__, "ss %p", ss);
655 654 FCOEI_LOG(__FUNCTION__, "sol_hash %p", ss->ss_sol_oxid_hash);
656 655 FCOEI_LOG(__FUNCTION__, "unsol_hash %p", ss->ss_unsol_rxid_hash);
657 656 ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
658 657 tmp_delay = FCOE_SEC2TICK(1) / 2;
659 658 last_clock = CURRENT_CLOCK;
660 659
661 660 /*
662 661 * If nobody reqeusts to terminate the watchdog, we will work forever
663 662 */
664 663 while (!(ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG)) {
665 664 /*
666 665 * We handle all asynchronous events serially
667 666 */
668 667 fcoei_process_events(ss);
669 668
670 669 /*
671 670 * To avoid to check timing too freqently, we check
672 671 * if we need skip timing stuff.
673 672 */
674 673 start_clock = CURRENT_CLOCK;
675 674 if ((start_clock - last_clock) < tmp_delay) {
676 675 goto end_timing;
677 676 } else {
678 677 last_clock = start_clock;
679 678 }
680 679
681 680 /*
682 681 * It's time to do timeout checking of solicited exchanges
683 682 */
684 683 if (ss->ss_sol_cnt == (&ss->ss_sol_cnt1)) {
685 684 if (ss->ss_sol_cnt2 == 0) {
686 685 ss->ss_sol_cnt = &ss->ss_sol_cnt2;
687 686 } else {
688 687 mod_hash_walk(ss->ss_sol_oxid_hash,
689 688 fcoei_xch_check, ss);
690 689 }
691 690 } else {
692 691 if (ss->ss_sol_cnt1 == 0) {
693 692 ss->ss_sol_cnt = &ss->ss_sol_cnt1;
694 693 } else {
695 694 mod_hash_walk(ss->ss_sol_oxid_hash,
696 695 fcoei_xch_check, ss);
697 696 }
698 697 }
699 698
700 699 /*
701 700 * It's time to do timeout checking of unsolicited exchange
702 701 */
703 702 if (ss->ss_unsol_cnt == (&ss->ss_unsol_cnt1)) {
704 703 if (ss->ss_unsol_cnt2 == 0) {
705 704 ss->ss_unsol_cnt = &ss->ss_unsol_cnt2;
706 705 } else {
707 706 mod_hash_walk(ss->ss_unsol_rxid_hash,
708 707 fcoei_xch_check, ss);
709 708 }
710 709 } else {
711 710 if (ss->ss_unsol_cnt1 == 0) {
712 711 ss->ss_unsol_cnt = &ss->ss_unsol_cnt1;
713 712 } else {
714 713 mod_hash_walk(ss->ss_unsol_rxid_hash,
715 714 fcoei_xch_check, ss);
716 715 }
717 716 }
718 717
719 718 /*
720 719 * Check if there are exchanges which are ready to complete
721 720 */
722 721 fcoei_handle_comp_xch_list(ss);
723 722
724 723 end_timing:
725 724 /*
726 725 * Wait for next cycle
727 726 */
728 727 mutex_enter(&ss->ss_watchdog_mutex);
729 728 ss->ss_flags |= SS_FLAG_WATCHDOG_IDLE;
730 729 if (!list_is_empty(&ss->ss_event_list)) {
731 730 goto skip_wait;
732 731 }
733 732
734 733 (void) cv_timedwait(&ss->ss_watchdog_cv,
735 734 &ss->ss_watchdog_mutex, CURRENT_CLOCK +
736 735 (clock_t)tmp_delay);
737 736 skip_wait:
738 737 ss->ss_flags &= ~SS_FLAG_WATCHDOG_IDLE;
739 738 mutex_exit(&ss->ss_watchdog_mutex);
740 739 }
741 740
742 741 /*
743 742 * Do clear work before exit
744 743 */
745 744 fcoei_clear_watchdog_jobs(ss);
746 745
747 746 /*
748 747 * Watchdog has stopped
749 748 */
750 749 ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
751 750 }
752 751
753 752 static void
754 753 fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss)
755 754 {
756 755 fcoei_event_t *ae;
757 756 fcoe_frame_t *frm;
758 757
759 758 mutex_enter(&ss->ss_watchdog_mutex);
760 759 while (!list_is_empty(&ss->ss_event_list)) {
761 760 ae = (fcoei_event_t *)list_head(&ss->ss_event_list);
762 761 list_remove(&ss->ss_event_list, ae);
763 762 switch (ae->ae_type) {
764 763 case AE_EVENT_SOL_FRAME:
765 764 frm = (fcoe_frame_t *)ae->ae_obj;
766 765 frm->frm_eport->eport_release_frame(frm);
767 766 break;
768 767
769 768 case AE_EVENT_UNSOL_FRAME:
770 769 frm = (fcoe_frame_t *)ae->ae_obj;
771 770 frm->frm_eport->eport_free_netb(frm->frm_netb);
772 771 frm->frm_eport->eport_release_frame(frm);
773 772 break;
774 773
775 774 case AE_EVENT_PORT:
776 775 atomic_dec_32(&ss->ss_port_event_counter);
777 776 /* FALLTHROUGH */
778 777
779 778 case AE_EVENT_RESET:
780 779 kmem_free(ae, sizeof (fcoei_event_t));
781 780 break;
782 781
783 782 case AE_EVENT_EXCHANGE:
784 783 /* FALLTHROUGH */
785 784
786 785 default:
787 786 break;
788 787 }
789 788 }
790 789
791 790 mod_hash_clear(ss->ss_unsol_rxid_hash);
792 791 mod_hash_clear(ss->ss_sol_oxid_hash);
793 792
794 793 while (!list_is_empty(&ss->ss_comp_xch_list)) {
795 794 (void) list_remove_head(&ss->ss_comp_xch_list);
796 795 }
797 796 mutex_exit(&ss->ss_watchdog_mutex);
798 797 }
799 798
800 799 /*
801 800 * fcoei_process_events
802 801 * Process the events one by one
803 802 *
804 803 * Input:
805 804 * ss = the soft state that will be processed
806 805 *
807 806 * Return:
808 807 * N/A
809 808 *
810 809 * Comment:
811 810 * N/A
812 811 */
813 812 static void
814 813 fcoei_process_events(fcoei_soft_state_t *ss)
815 814 {
816 815 fcoei_event_t *ae = NULL;
817 816
818 817 /*
819 818 * It's the only place to delete node from ss_event_list, so we needn't
820 819 * hold mutex to check if the list is empty.
821 820 */
822 821 ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
823 822 while (list_is_empty(&ss->ss_event_list) == B_FALSE) {
824 823 mutex_enter(&ss->ss_watchdog_mutex);
825 824 ae = (fcoei_event_t *)list_remove_head(&ss->ss_event_list);
826 825 mutex_exit(&ss->ss_watchdog_mutex);
827 826
828 827 switch (ae->ae_type) {
829 828 case AE_EVENT_SOL_FRAME:
830 829 fcoei_handle_sol_frame_done((fcoe_frame_t *)ae->ae_obj);
831 830 break;
832 831
833 832 case AE_EVENT_UNSOL_FRAME:
834 833 fcoei_process_unsol_frame((fcoe_frame_t *)ae->ae_obj);
835 834 break;
836 835
837 836 case AE_EVENT_EXCHANGE:
838 837 fcoei_process_event_exchange(ae);
839 838 break;
840 839
841 840 case AE_EVENT_PORT:
842 841 fcoei_process_event_port(ae);
843 842 break;
844 843
845 844 case AE_EVENT_RESET:
846 845 fcoei_process_event_reset(ae);
847 846 break;
848 847
849 848 default:
850 849 FCOEI_LOG(__FUNCTION__, "unsupported events");
851 850 }
852 851
853 852 }
854 853 }
855 854
856 855 /*
857 856 * fcoei_handle_tmout_xch_list
858 857 * Complete every exchange in the timed-out xch list of the soft state
859 858 *
860 859 * Input:
861 860 * ss = the soft state that need be handled
862 861 *
863 862 * Return:
864 863 * N/A
865 864 *
866 865 * Comment:
867 866 * When mod_hash_walk is in progress, we can't change the hashtable.
868 867 * This is post-walk handling of exchange timing
869 868 */
870 869 void
871 870 fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss)
872 871 {
873 872 fcoei_exchange_t *xch = NULL;
874 873
875 874 while ((xch = list_remove_head(&ss->ss_comp_xch_list)) != NULL) {
876 875 fcoei_complete_xch(xch, NULL, xch->xch_fpkt->pkt_state,
877 876 xch->xch_fpkt->pkt_reason);
878 877 }
879 878 }
880 879
881 880 /*
882 881 * fcoei_xch_check
883 882 * Check if the exchange timed out or link is down
884 883 *
885 884 * Input:
886 885 * key = rxid of the unsolicited exchange
887 886 * val = the unsolicited exchange
888 887 * arg = the soft state
889 888 *
890 889 * Return:
891 890 * MH_WALK_CONTINUE = continue to walk
892 891 *
893 892 * Comment:
894 893 * We need send ABTS for timed-out for solicited exchange
895 894 * If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED
896 895 * If the link is down, we think it has timed out too.
897 896 */
898 897 /* ARGSUSED */
899 898 static uint32_t
900 899 fcoei_xch_check(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
901 900 {
902 901 fcoei_exchange_t *xch = (fcoei_exchange_t *)val;
903 902
904 903 ASSERT(xch->xch_ss == arg);
905 904 if ((xch->xch_end_tick < CURRENT_CLOCK) &&
906 905 (xch->xch_ss->ss_link_state != FC_STATE_OFFLINE)) {
907 906 if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
908 907 ASSERT(xch->xch_oxid == CMHK(key));
909 908 /*
910 909 * It's solicited exchange
911 910 */
912 911 fcoei_abts_exchange(xch);
913 912 if (LA_ELS_FLOGI == ((ls_code_t *)(void *)
914 913 xch->xch_fpkt->pkt_cmd)->ls_code) {
915 914 /*
916 915 * It's solicited FLOGI
917 916 */
918 917 xch->xch_ss->ss_flags |= SS_FLAG_FLOGI_FAILED;
919 918 }
920 919 }
921 920
922 921 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x timed out",
923 922 xch->xch_oxid, xch->xch_rxid);
924 923 xch->xch_flags |= XCH_FLAG_TMOUT;
925 924 xch->xch_fpkt->pkt_state = FC_PKT_TIMEOUT;
926 925 xch->xch_fpkt->pkt_reason = FC_REASON_ABORTED;
927 926 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
928 927 } else if (xch->xch_ss->ss_link_state == FC_STATE_OFFLINE) {
929 928 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x offline complete",
930 929 xch->xch_oxid, xch->xch_rxid);
931 930 xch->xch_flags |= XCH_FLAG_TMOUT;
932 931 xch->xch_fpkt->pkt_state = FC_PKT_PORT_OFFLINE;
933 932 xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
934 933 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
935 934 }
936 935
937 936 return (MH_WALK_CONTINUE);
938 937 }
939 938
940 939 /*
941 940 * fcoei_init_ifm
942 941 * initialize fcoei_frame
943 942 *
944 943 * Input:
945 944 * frm = the frame that ifm need link to
946 945 * xch = the exchange that ifm need link to
947 946 *
948 947 * Return:
949 948 * N/A
950 949 *
951 950 * Comment:
952 951 * For solicited frames, it's called after FC frame header initialization
953 952 * For unsolicited frames, it's called just after the frame enters fcoei
954 953 */
955 954 void
956 955 fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch)
957 956 {
958 957 FRM2IFM(frm)->ifm_frm = frm;
959 958 FRM2IFM(frm)->ifm_xch = xch;
960 959 FRM2IFM(frm)->ifm_rctl = FRM_R_CTL(frm);
961 960 }
962 961
963 962 /*
964 963 * fcoei_trigger_fp_attach
965 964 * Trigger fp_attach for this fcoei port
966 965 *
967 966 * Input:
968 967 * arg = the soft state that fp will attach
969 968 *
970 969 * Return:
971 970 * N/A
972 971 *
973 972 * Comment:
974 973 * N/A
975 974 */
976 975 static void
977 976 fcoei_trigger_fp_attach(void * arg)
978 977 {
979 978 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)arg;
980 979 dev_info_t *child = NULL;
981 980 int rval = NDI_FAILURE;
982 981
983 982 ndi_devi_alloc_sleep(ss->ss_dip, "fp", DEVI_PSEUDO_NODEID, &child);
984 983 if (child == NULL) {
985 984 FCOEI_LOG(__FUNCTION__, "can't alloc dev_info");
986 985 return;
987 986 }
988 987
989 988 /*
990 989 * fp/fctl need this property
991 990 */
992 991 if (ddi_prop_update_string(DDI_DEV_T_NONE, child,
993 992 "bus-addr", "0,0") != DDI_PROP_SUCCESS) {
994 993 FCOEI_LOG(__FUNCTION__, "update bus-addr failed");
995 994 (void) ndi_devi_free(child);
996 995 return;
997 996 }
998 997
999 998 /*
1000 999 * If it's physical HBA, fp.conf will register the property.
1001 1000 * fcoei is one software HBA, so we need register it manually
1002 1001 */
1003 1002 if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
1004 1003 "port", 0) != DDI_PROP_SUCCESS) {
1005 1004 FCOEI_LOG(__FUNCTION__, "update port failed");
1006 1005 (void) ndi_devi_free(child);
1007 1006 return;
1008 1007 }
1009 1008
1010 1009 /*
1011 1010 * It will call fp_attach eventually
1012 1011 */
1013 1012 rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
1014 1013 ss->ss_flags &= ~SS_FLAG_TRIGGER_FP_ATTACH;
1015 1014 if (rval != NDI_SUCCESS) {
1016 1015 FCOEI_LOG(__FUNCTION__, "devi_online: %d", rval);
1017 1016 } else {
1018 1017 FCOEI_LOG(__FUNCTION__, "triggered successfully");
1019 1018 }
1020 1019 }
1021 1020
1022 1021 /*
1023 1022 * fcoei_abts_exchange
1024 1023 * Send ABTS to abort solicited exchange
1025 1024 *
1026 1025 * Input:
1027 1026 * xch = the exchange that will be aborted
1028 1027 *
1029 1028 * Return:
1030 1029 * N/A
1031 1030 *
1032 1031 * Comment:
1033 1032 * ABTS frame uses the same oxid as the exchange
1034 1033 */
1035 1034 static void
1036 1035 fcoei_abts_exchange(fcoei_exchange_t *xch)
1037 1036 {
1038 1037 fc_packet_t *fpkt = xch->xch_fpkt;
1039 1038 fcoe_frame_t *frm = NULL;
1040 1039
1041 1040 /*
1042 1041 * BLS_ABTS doesn't contain any other payload except FCFH
1043 1042 */
1044 1043 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1045 1044 FCFH_SIZE, NULL);
1046 1045 if (frm == NULL) {
1047 1046 FCOEI_LOG(__FUNCTION__, "can't alloc frame: %p", xch);
1048 1047 return;
1049 1048 }
1050 1049
1051 1050 FFM_R_CTL(0x81, frm);
1052 1051 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1053 1052 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1054 1053 FFM_F_CTL(0x090000, frm);
1055 1054 FFM_SEQ_ID(0x01, frm);
1056 1055 FFM_OXID(xch->xch_oxid, frm);
1057 1056 FFM_RXID(xch->xch_rxid, frm);
1058 1057 fcoei_init_ifm(frm, xch);
1059 1058 xch->xch_ss->ss_eport->eport_tx_frame(frm);
1060 1059 }
1061 1060
1062 1061 /*
1063 1062 * fcoei_complete_xch
1064 1063 * Complete the exchange
1065 1064 *
1066 1065 * Input:
1067 1066 * xch = the exchange that will be completed
1068 1067 * frm = newly-allocated frame that has not been submitted
1069 1068 * pkt_state = LV fpkt state
1070 1069 * pkt_reason = LV fpkt reason
1071 1070 *
1072 1071 * Return:
1073 1072 * N/A
1074 1073 *
1075 1074 * Comment:
1076 1075 * N/A
1077 1076 */
1078 1077 void
1079 1078 fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm,
1080 1079 uint8_t pkt_state, uint8_t pkt_reason)
1081 1080 {
1082 1081 mod_hash_val_t val;
1083 1082
1084 1083 if (pkt_state != FC_PKT_SUCCESS) {
1085 1084 FCOEI_LOG(__FUNCTION__, "FHDR: %x/%x/%x, %x/%x/%x",
1086 1085 xch->xch_fpkt->pkt_cmd_fhdr.r_ctl,
1087 1086 xch->xch_fpkt->pkt_cmd_fhdr.f_ctl,
1088 1087 xch->xch_fpkt->pkt_cmd_fhdr.type,
1089 1088 xch->xch_fpkt->pkt_resp_fhdr.r_ctl,
1090 1089 xch->xch_fpkt->pkt_resp_fhdr.f_ctl,
1091 1090 xch->xch_fpkt->pkt_resp_fhdr.type);
1092 1091 FCOEI_LOG(__FUNCTION__, "%p/%p/%x/%x",
1093 1092 xch, frm, pkt_state, pkt_reason);
1094 1093 }
1095 1094
1096 1095 if (frm != NULL) {
1097 1096 /*
1098 1097 * It's newly-allocated frame , which we haven't sent out
1099 1098 */
1100 1099 xch->xch_ss->ss_eport->eport_free_netb(frm->frm_netb);
1101 1100 xch->xch_ss->ss_eport->eport_release_frame(frm);
1102 1101 FCOEI_LOG(__FUNCTION__, "xch: %p, not submitted", xch);
1103 1102 }
1104 1103
1105 1104 /*
1106 1105 * If xch is in hash table, we need remove it
1107 1106 */
1108 1107 if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
1109 1108 (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
1110 1109 FMHK(xch->xch_oxid), &val);
1111 1110 ASSERT((fcoei_exchange_t *)val == xch);
1112 1111 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
1113 1112 } else if (xch->xch_flags & XCH_FLAG_IN_UNSOL_HASH) {
1114 1113 (void) mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
1115 1114 FMHK(xch->xch_rxid), &val);
1116 1115 ASSERT((fcoei_exchange_t *)val == xch);
1117 1116 xch->xch_flags &= ~XCH_FLAG_IN_UNSOL_HASH;
1118 1117 } else {
1119 1118 FCOEI_LOG(__FUNCTION__, "xch not in any hash: %p", xch);
1120 1119 }
1121 1120
1122 1121 xch->xch_fpkt->pkt_state = pkt_state;
1123 1122 xch->xch_fpkt->pkt_reason = pkt_reason;
1124 1123 if (xch->xch_fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
1125 1124 FCOEI_LOG(__FUNCTION__, "polled xch is done: %p", xch);
1126 1125 sema_v(&xch->xch_sema);
1127 1126 } else {
1128 1127 xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
1129 1128 }
1130 1129 }
↓ open down ↓ |
997 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX