0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "efc.h"
0012
0013 int
0014 efc_domain_cb(void *arg, int event, void *data)
0015 {
0016 struct efc *efc = arg;
0017 struct efc_domain *domain = NULL;
0018 int rc = 0;
0019 unsigned long flags = 0;
0020
0021 if (event != EFC_HW_DOMAIN_FOUND)
0022 domain = data;
0023
0024
0025 spin_lock_irqsave(&efc->lock, flags);
0026 switch (event) {
0027 case EFC_HW_DOMAIN_FOUND: {
0028 u64 fcf_wwn = 0;
0029 struct efc_domain_record *drec = data;
0030
0031
0032 fcf_wwn = be64_to_cpu(*((__be64 *)drec->wwn));
0033
0034 efc_log_debug(efc, "Domain found: wwn %016llX\n", fcf_wwn);
0035
0036
0037 domain = efc->domain;
0038 if (!domain) {
0039 domain = efc_domain_alloc(efc, fcf_wwn);
0040 if (!domain) {
0041 efc_log_err(efc, "efc_domain_alloc() failed\n");
0042 rc = -1;
0043 break;
0044 }
0045 efc_sm_transition(&domain->drvsm, __efc_domain_init,
0046 NULL);
0047 }
0048 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FOUND, drec);
0049 break;
0050 }
0051
0052 case EFC_HW_DOMAIN_LOST:
0053 domain_trace(domain, "EFC_HW_DOMAIN_LOST:\n");
0054 efc->hold_frames = true;
0055 efc_domain_post_event(domain, EFC_EVT_DOMAIN_LOST, NULL);
0056 break;
0057
0058 case EFC_HW_DOMAIN_ALLOC_OK:
0059 domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_OK:\n");
0060 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_OK, NULL);
0061 break;
0062
0063 case EFC_HW_DOMAIN_ALLOC_FAIL:
0064 domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_FAIL:\n");
0065 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_FAIL,
0066 NULL);
0067 break;
0068
0069 case EFC_HW_DOMAIN_ATTACH_OK:
0070 domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_OK:\n");
0071 efc_domain_post_event(domain, EFC_EVT_DOMAIN_ATTACH_OK, NULL);
0072 break;
0073
0074 case EFC_HW_DOMAIN_ATTACH_FAIL:
0075 domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_FAIL:\n");
0076 efc_domain_post_event(domain,
0077 EFC_EVT_DOMAIN_ATTACH_FAIL, NULL);
0078 break;
0079
0080 case EFC_HW_DOMAIN_FREE_OK:
0081 domain_trace(domain, "EFC_HW_DOMAIN_FREE_OK:\n");
0082 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_OK, NULL);
0083 break;
0084
0085 case EFC_HW_DOMAIN_FREE_FAIL:
0086 domain_trace(domain, "EFC_HW_DOMAIN_FREE_FAIL:\n");
0087 efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_FAIL, NULL);
0088 break;
0089
0090 default:
0091 efc_log_warn(efc, "unsupported event %#x\n", event);
0092 }
0093 spin_unlock_irqrestore(&efc->lock, flags);
0094
0095 if (efc->domain && domain->req_accept_frames) {
0096 domain->req_accept_frames = false;
0097 efc->hold_frames = false;
0098 }
0099
0100 return rc;
0101 }
0102
0103 static void
0104 _efc_domain_free(struct kref *arg)
0105 {
0106 struct efc_domain *domain = container_of(arg, struct efc_domain, ref);
0107 struct efc *efc = domain->efc;
0108
0109 if (efc->domain_free_cb)
0110 (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg);
0111
0112 kfree(domain);
0113 }
0114
0115 void
0116 efc_domain_free(struct efc_domain *domain)
0117 {
0118 struct efc *efc;
0119
0120 efc = domain->efc;
0121
0122
0123 efc->hold_frames = false;
0124
0125 efc_log_debug(efc, "Domain free: wwn %016llX\n", domain->fcf_wwn);
0126
0127 xa_destroy(&domain->lookup);
0128 efc->domain = NULL;
0129 kref_put(&domain->ref, domain->release);
0130 }
0131
0132 struct efc_domain *
0133 efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn)
0134 {
0135 struct efc_domain *domain;
0136
0137 domain = kzalloc(sizeof(*domain), GFP_ATOMIC);
0138 if (!domain)
0139 return NULL;
0140
0141 domain->efc = efc;
0142 domain->drvsm.app = domain;
0143
0144
0145 kref_init(&domain->ref);
0146 domain->release = _efc_domain_free;
0147
0148 xa_init(&domain->lookup);
0149
0150 INIT_LIST_HEAD(&domain->nport_list);
0151 efc->domain = domain;
0152 domain->fcf_wwn = fcf_wwn;
0153 efc_log_debug(efc, "Domain allocated: wwn %016llX\n", domain->fcf_wwn);
0154
0155 return domain;
0156 }
0157
0158 void
0159 efc_register_domain_free_cb(struct efc *efc,
0160 void (*callback)(struct efc *efc, void *arg),
0161 void *arg)
0162 {
0163
0164 efc->domain_free_cb = callback;
0165 efc->domain_free_cb_arg = arg;
0166 if (!efc->domain && callback)
0167 (*callback)(efc, arg);
0168 }
0169
0170 static void
0171 __efc_domain_common(const char *funcname, struct efc_sm_ctx *ctx,
0172 enum efc_sm_event evt, void *arg)
0173 {
0174 struct efc_domain *domain = ctx->app;
0175
0176 switch (evt) {
0177 case EFC_EVT_ENTER:
0178 case EFC_EVT_REENTER:
0179 case EFC_EVT_EXIT:
0180 case EFC_EVT_ALL_CHILD_NODES_FREE:
0181
0182
0183
0184
0185 break;
0186 default:
0187 efc_log_warn(domain->efc, "%-20s %-20s not handled\n",
0188 funcname, efc_sm_event_name(evt));
0189 }
0190 }
0191
0192 static void
0193 __efc_domain_common_shutdown(const char *funcname, struct efc_sm_ctx *ctx,
0194 enum efc_sm_event evt, void *arg)
0195 {
0196 struct efc_domain *domain = ctx->app;
0197
0198 switch (evt) {
0199 case EFC_EVT_ENTER:
0200 case EFC_EVT_REENTER:
0201 case EFC_EVT_EXIT:
0202 break;
0203 case EFC_EVT_DOMAIN_FOUND:
0204
0205 memcpy(&domain->pending_drec, arg,
0206 sizeof(domain->pending_drec));
0207 domain->domain_found_pending = true;
0208 break;
0209 case EFC_EVT_DOMAIN_LOST:
0210
0211 domain->domain_found_pending = false;
0212 break;
0213
0214 default:
0215 efc_log_warn(domain->efc, "%-20s %-20s not handled\n",
0216 funcname, efc_sm_event_name(evt));
0217 }
0218 }
0219
0220 #define std_domain_state_decl(...)\
0221 struct efc_domain *domain = NULL;\
0222 struct efc *efc = NULL;\
0223 \
0224 WARN_ON(!ctx || !ctx->app);\
0225 domain = ctx->app;\
0226 WARN_ON(!domain->efc);\
0227 efc = domain->efc
0228
0229 void
0230 __efc_domain_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
0231 void *arg)
0232 {
0233 std_domain_state_decl();
0234
0235 domain_sm_trace(domain);
0236
0237 switch (evt) {
0238 case EFC_EVT_ENTER:
0239 domain->attached = false;
0240 break;
0241
0242 case EFC_EVT_DOMAIN_FOUND: {
0243 u32 i;
0244 struct efc_domain_record *drec = arg;
0245 struct efc_nport *nport;
0246
0247 u64 my_wwnn = efc->req_wwnn;
0248 u64 my_wwpn = efc->req_wwpn;
0249 __be64 bewwpn;
0250
0251 if (my_wwpn == 0 || my_wwnn == 0) {
0252 efc_log_debug(efc, "using default hardware WWN config\n");
0253 my_wwpn = efc->def_wwpn;
0254 my_wwnn = efc->def_wwnn;
0255 }
0256
0257 efc_log_debug(efc, "Create nport WWPN %016llX WWNN %016llX\n",
0258 my_wwpn, my_wwnn);
0259
0260
0261 nport = efc_nport_alloc(domain, my_wwpn, my_wwnn, U32_MAX,
0262 efc->enable_ini, efc->enable_tgt);
0263
0264 if (!nport) {
0265 efc_log_err(efc, "efc_nport_alloc() failed\n");
0266 break;
0267 }
0268 efc_sm_transition(&nport->sm, __efc_nport_allocated, NULL);
0269
0270 bewwpn = cpu_to_be64(nport->wwpn);
0271
0272
0273
0274
0275 if (efc_cmd_nport_alloc(efc, nport, NULL, (uint8_t *)&bewwpn)) {
0276 efc_log_err(efc, "Can't allocate port\n");
0277 efc_nport_free(nport);
0278 break;
0279 }
0280
0281 domain->is_loop = drec->is_loop;
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 domain->is_nlport = drec->map.loop[1] == 0x00;
0292
0293 if (!domain->is_loop) {
0294
0295 if (efc_cmd_domain_alloc(efc, domain, drec->index)) {
0296 efc_log_err(efc,
0297 "Failed to initiate HW domain allocation\n");
0298 break;
0299 }
0300 efc_sm_transition(ctx, __efc_domain_wait_alloc, arg);
0301 break;
0302 }
0303
0304 efc_log_debug(efc, "%s fc_id=%#x speed=%d\n",
0305 drec->is_loop ?
0306 (domain->is_nlport ?
0307 "public-loop" : "loop") : "other",
0308 drec->fc_id, drec->speed);
0309
0310 nport->fc_id = drec->fc_id;
0311 nport->topology = EFC_NPORT_TOPO_FC_AL;
0312 snprintf(nport->display_name, sizeof(nport->display_name),
0313 "s%06x", drec->fc_id);
0314
0315 if (efc->enable_ini) {
0316 u32 count = drec->map.loop[0];
0317
0318 efc_log_debug(efc, "%d position map entries\n",
0319 count);
0320 for (i = 1; i <= count; i++) {
0321 if (drec->map.loop[i] != drec->fc_id) {
0322 struct efc_node *node;
0323
0324 efc_log_debug(efc, "%#x -> %#x\n",
0325 drec->fc_id,
0326 drec->map.loop[i]);
0327 node = efc_node_alloc(nport,
0328 drec->map.loop[i],
0329 false, true);
0330 if (!node) {
0331 efc_log_err(efc,
0332 "efc_node_alloc() failed\n");
0333 break;
0334 }
0335 efc_node_transition(node,
0336 __efc_d_wait_loop,
0337 NULL);
0338 }
0339 }
0340 }
0341
0342
0343 if (efc_cmd_domain_alloc(efc, domain, drec->index)) {
0344 efc_log_err(efc,
0345 "Failed to initiate HW domain allocation\n");
0346 break;
0347 }
0348 efc_sm_transition(ctx, __efc_domain_wait_alloc, arg);
0349 break;
0350 }
0351 default:
0352 __efc_domain_common(__func__, ctx, evt, arg);
0353 }
0354 }
0355
0356 void
0357 __efc_domain_wait_alloc(struct efc_sm_ctx *ctx,
0358 enum efc_sm_event evt, void *arg)
0359 {
0360 std_domain_state_decl();
0361
0362 domain_sm_trace(domain);
0363
0364 switch (evt) {
0365 case EFC_EVT_DOMAIN_ALLOC_OK: {
0366 struct fc_els_flogi *sp;
0367 struct efc_nport *nport;
0368
0369 nport = domain->nport;
0370 if (WARN_ON(!nport))
0371 return;
0372
0373 sp = (struct fc_els_flogi *)nport->service_params;
0374
0375
0376 memcpy(domain->service_params + 4, domain->dma.virt,
0377 sizeof(struct fc_els_flogi) - 4);
0378 memcpy(nport->service_params + 4, domain->dma.virt,
0379 sizeof(struct fc_els_flogi) - 4);
0380
0381
0382
0383
0384
0385 sp->fl_wwpn = cpu_to_be64(nport->wwpn);
0386 sp->fl_wwnn = cpu_to_be64(nport->wwnn);
0387
0388
0389
0390
0391
0392 if (domain->is_loop && !domain->is_nlport) {
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 efc_sm_transition(ctx, __efc_domain_allocated, NULL);
0405 __efc_domain_attach_internal(domain, nport->fc_id);
0406 break;
0407 }
0408 {
0409 struct efc_node *node;
0410
0411
0412 node = efc_node_find(nport, FC_FID_FLOGI);
0413 if (node) {
0414 efc_log_err(efc,
0415 "Fabric Controller node already exists\n");
0416 break;
0417 }
0418 node = efc_node_alloc(nport, FC_FID_FLOGI,
0419 false, false);
0420 if (!node) {
0421 efc_log_err(efc,
0422 "Error: efc_node_alloc() failed\n");
0423 } else {
0424 efc_node_transition(node,
0425 __efc_fabric_init, NULL);
0426 }
0427
0428 domain->req_accept_frames = true;
0429 }
0430
0431 efc_sm_transition(ctx, __efc_domain_allocated, NULL);
0432 break;
0433 }
0434
0435 case EFC_EVT_DOMAIN_ALLOC_FAIL:
0436 efc_log_err(efc, "%s recv'd waiting for DOMAIN_ALLOC_OK;",
0437 efc_sm_event_name(evt));
0438 efc_log_err(efc, "shutting down domain\n");
0439 domain->req_domain_free = true;
0440 break;
0441
0442 case EFC_EVT_DOMAIN_FOUND:
0443
0444 break;
0445
0446 case EFC_EVT_DOMAIN_LOST:
0447 efc_log_debug(efc,
0448 "%s received while waiting for hw_domain_alloc()\n",
0449 efc_sm_event_name(evt));
0450 efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL);
0451 break;
0452
0453 default:
0454 __efc_domain_common(__func__, ctx, evt, arg);
0455 }
0456 }
0457
0458 void
0459 __efc_domain_allocated(struct efc_sm_ctx *ctx,
0460 enum efc_sm_event evt, void *arg)
0461 {
0462 std_domain_state_decl();
0463
0464 domain_sm_trace(domain);
0465
0466 switch (evt) {
0467 case EFC_EVT_DOMAIN_REQ_ATTACH: {
0468 int rc = 0;
0469 u32 fc_id;
0470
0471 if (WARN_ON(!arg))
0472 return;
0473
0474 fc_id = *((u32 *)arg);
0475 efc_log_debug(efc, "Requesting hw domain attach fc_id x%x\n",
0476 fc_id);
0477
0478 rc = xa_err(xa_store(&domain->lookup, fc_id, domain->nport,
0479 GFP_ATOMIC));
0480 if (rc) {
0481 efc_log_err(efc, "Sport lookup store failed: %d\n", rc);
0482 return;
0483 }
0484
0485
0486 efc_node_fcid_display(fc_id, domain->nport->display_name,
0487 sizeof(domain->nport->display_name));
0488
0489
0490 rc = efc_cmd_domain_attach(efc, domain, fc_id);
0491 if (rc) {
0492 efc_log_err(efc, "efc_hw_domain_attach failed: %d\n",
0493 rc);
0494 return;
0495 }
0496
0497 efc_sm_transition(ctx, __efc_domain_wait_attach, NULL);
0498 break;
0499 }
0500
0501 case EFC_EVT_DOMAIN_FOUND:
0502
0503 efc_log_err(efc, "%s: evt: %d should not happen\n",
0504 __func__, evt);
0505 break;
0506
0507 case EFC_EVT_DOMAIN_LOST: {
0508 efc_log_debug(efc,
0509 "%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n",
0510 efc_sm_event_name(evt));
0511 if (!list_empty(&domain->nport_list)) {
0512
0513
0514
0515
0516
0517 struct efc_nport *nport = NULL, *nport_next = NULL;
0518
0519 efc_sm_transition(ctx, __efc_domain_wait_nports_free,
0520 NULL);
0521 list_for_each_entry_safe(nport, nport_next,
0522 &domain->nport_list,
0523 list_entry) {
0524 efc_sm_post_event(&nport->sm,
0525 EFC_EVT_SHUTDOWN, NULL);
0526 }
0527 } else {
0528
0529 efc_sm_transition(ctx, __efc_domain_wait_shutdown,
0530 NULL);
0531 if (efc_cmd_domain_free(efc, domain))
0532 efc_log_err(efc, "hw_domain_free failed\n");
0533 }
0534
0535 break;
0536 }
0537
0538 default:
0539 __efc_domain_common(__func__, ctx, evt, arg);
0540 }
0541 }
0542
0543 void
0544 __efc_domain_wait_attach(struct efc_sm_ctx *ctx,
0545 enum efc_sm_event evt, void *arg)
0546 {
0547 std_domain_state_decl();
0548
0549 domain_sm_trace(domain);
0550
0551 switch (evt) {
0552 case EFC_EVT_DOMAIN_ATTACH_OK: {
0553 struct efc_node *node = NULL;
0554 struct efc_nport *nport, *next_nport;
0555 unsigned long index;
0556
0557
0558
0559
0560
0561 domain->domain_notify_pend = true;
0562
0563
0564 domain->attached = true;
0565
0566
0567
0568 efc_sm_transition(ctx, __efc_domain_ready, NULL);
0569
0570
0571 domain->req_accept_frames = true;
0572
0573
0574
0575
0576
0577
0578
0579 list_for_each_entry_safe(nport, next_nport,
0580 &domain->nport_list, list_entry) {
0581 xa_for_each(&nport->lookup, index, node) {
0582 efc_node_post_event(node,
0583 EFC_EVT_DOMAIN_ATTACH_OK,
0584 NULL);
0585 }
0586 }
0587 domain->domain_notify_pend = false;
0588 break;
0589 }
0590
0591 case EFC_EVT_DOMAIN_ATTACH_FAIL:
0592 efc_log_debug(efc,
0593 "%s received while waiting for hw attach\n",
0594 efc_sm_event_name(evt));
0595 break;
0596
0597 case EFC_EVT_DOMAIN_FOUND:
0598
0599 efc_log_err(efc, "%s: evt: %d should not happen\n",
0600 __func__, evt);
0601 break;
0602
0603 case EFC_EVT_DOMAIN_LOST:
0604
0605
0606
0607
0608
0609 efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL);
0610 break;
0611
0612 case EFC_EVT_DOMAIN_REQ_ATTACH:
0613
0614
0615
0616
0617 break;
0618
0619 default:
0620 __efc_domain_common(__func__, ctx, evt, arg);
0621 }
0622 }
0623
0624 void
0625 __efc_domain_ready(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
0626 {
0627 std_domain_state_decl();
0628
0629 domain_sm_trace(domain);
0630
0631 switch (evt) {
0632 case EFC_EVT_ENTER: {
0633
0634 if (efc_vport_start(domain)) {
0635 efc_log_debug(domain->efc,
0636 "efc_vport_start didn't start vports\n");
0637 }
0638 break;
0639 }
0640 case EFC_EVT_DOMAIN_LOST: {
0641 if (!list_empty(&domain->nport_list)) {
0642
0643
0644
0645
0646 struct efc_nport *nport = NULL, *nport_next = NULL;
0647
0648 efc_sm_transition(ctx, __efc_domain_wait_nports_free,
0649 NULL);
0650 list_for_each_entry_safe(nport, nport_next,
0651 &domain->nport_list,
0652 list_entry) {
0653 efc_sm_post_event(&nport->sm,
0654 EFC_EVT_SHUTDOWN, NULL);
0655 }
0656 } else {
0657
0658 efc_sm_transition(ctx, __efc_domain_wait_shutdown,
0659 NULL);
0660 if (efc_cmd_domain_free(efc, domain))
0661 efc_log_err(efc, "hw_domain_free failed\n");
0662 }
0663 break;
0664 }
0665
0666 case EFC_EVT_DOMAIN_FOUND:
0667
0668 efc_log_err(efc, "%s: evt: %d should not happen\n",
0669 __func__, evt);
0670 break;
0671
0672 case EFC_EVT_DOMAIN_REQ_ATTACH: {
0673
0674 u32 fc_id;
0675
0676 fc_id = *((u32 *)arg);
0677
0678
0679 WARN_ON(!domain->attached);
0680
0681
0682
0683
0684
0685 WARN_ON(domain->nport->fc_id != fc_id);
0686 break;
0687 }
0688
0689 default:
0690 __efc_domain_common(__func__, ctx, evt, arg);
0691 }
0692 }
0693
0694 void
0695 __efc_domain_wait_nports_free(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
0696 void *arg)
0697 {
0698 std_domain_state_decl();
0699
0700 domain_sm_trace(domain);
0701
0702
0703 switch (evt) {
0704 case EFC_EVT_ALL_CHILD_NODES_FREE: {
0705 int rc;
0706
0707
0708 efc_sm_transition(ctx, __efc_domain_wait_shutdown, NULL);
0709
0710
0711 rc = efc_cmd_domain_free(efc, domain);
0712 if (rc) {
0713 efc_log_err(efc, "efc_hw_domain_free() failed: %d\n",
0714 rc);
0715 }
0716 break;
0717 }
0718 default:
0719 __efc_domain_common_shutdown(__func__, ctx, evt, arg);
0720 }
0721 }
0722
0723 void
0724 __efc_domain_wait_shutdown(struct efc_sm_ctx *ctx,
0725 enum efc_sm_event evt, void *arg)
0726 {
0727 std_domain_state_decl();
0728
0729 domain_sm_trace(domain);
0730
0731 switch (evt) {
0732 case EFC_EVT_DOMAIN_FREE_OK:
0733
0734 if (domain->domain_found_pending) {
0735
0736
0737
0738
0739
0740
0741
0742 u64 fcf_wwn = domain->fcf_wwn;
0743 struct efc_domain_record drec = domain->pending_drec;
0744
0745 efc_log_debug(efc, "Reallocating domain\n");
0746 domain->req_domain_free = true;
0747 domain = efc_domain_alloc(efc, fcf_wwn);
0748
0749 if (!domain) {
0750 efc_log_err(efc,
0751 "efc_domain_alloc() failed\n");
0752 return;
0753 }
0754
0755
0756
0757
0758
0759
0760 efc_sm_transition(&domain->drvsm, __efc_domain_init,
0761 NULL);
0762 efc_sm_post_event(&domain->drvsm,
0763 EFC_EVT_DOMAIN_FOUND, &drec);
0764 } else {
0765 domain->req_domain_free = true;
0766 }
0767 break;
0768 default:
0769 __efc_domain_common_shutdown(__func__, ctx, evt, arg);
0770 }
0771 }
0772
0773 void
0774 __efc_domain_wait_domain_lost(struct efc_sm_ctx *ctx,
0775 enum efc_sm_event evt, void *arg)
0776 {
0777 std_domain_state_decl();
0778
0779 domain_sm_trace(domain);
0780
0781
0782
0783
0784
0785 switch (evt) {
0786 case EFC_EVT_DOMAIN_ALLOC_OK:
0787 case EFC_EVT_DOMAIN_ATTACH_OK: {
0788 if (!list_empty(&domain->nport_list)) {
0789
0790
0791
0792
0793 struct efc_nport *nport = NULL, *nport_next = NULL;
0794
0795 efc_sm_transition(ctx, __efc_domain_wait_nports_free,
0796 NULL);
0797 list_for_each_entry_safe(nport, nport_next,
0798 &domain->nport_list,
0799 list_entry) {
0800 efc_sm_post_event(&nport->sm,
0801 EFC_EVT_SHUTDOWN, NULL);
0802 }
0803 } else {
0804
0805 efc_sm_transition(ctx, __efc_domain_wait_shutdown,
0806 NULL);
0807 if (efc_cmd_domain_free(efc, domain))
0808 efc_log_err(efc, "hw_domain_free() failed\n");
0809 }
0810 break;
0811 }
0812 case EFC_EVT_DOMAIN_ALLOC_FAIL:
0813 case EFC_EVT_DOMAIN_ATTACH_FAIL:
0814 efc_log_err(efc, "[domain] %-20s: failed\n",
0815 efc_sm_event_name(evt));
0816 break;
0817
0818 default:
0819 __efc_domain_common_shutdown(__func__, ctx, evt, arg);
0820 }
0821 }
0822
0823 void
0824 __efc_domain_attach_internal(struct efc_domain *domain, u32 s_id)
0825 {
0826 memcpy(domain->dma.virt,
0827 ((uint8_t *)domain->flogi_service_params) + 4,
0828 sizeof(struct fc_els_flogi) - 4);
0829 (void)efc_sm_post_event(&domain->drvsm, EFC_EVT_DOMAIN_REQ_ATTACH,
0830 &s_id);
0831 }
0832
0833 void
0834 efc_domain_attach(struct efc_domain *domain, u32 s_id)
0835 {
0836 __efc_domain_attach_internal(domain, s_id);
0837 }
0838
0839 int
0840 efc_domain_post_event(struct efc_domain *domain,
0841 enum efc_sm_event event, void *arg)
0842 {
0843 int rc;
0844 bool req_domain_free;
0845
0846 rc = efc_sm_post_event(&domain->drvsm, event, arg);
0847
0848 req_domain_free = domain->req_domain_free;
0849 domain->req_domain_free = false;
0850
0851 if (req_domain_free)
0852 efc_domain_free(domain);
0853
0854 return rc;
0855 }
0856
0857 static void
0858 efct_domain_process_pending(struct efc_domain *domain)
0859 {
0860 struct efc *efc = domain->efc;
0861 struct efc_hw_sequence *seq = NULL;
0862 u32 processed = 0;
0863 unsigned long flags = 0;
0864
0865 for (;;) {
0866
0867
0868
0869
0870 if (efc->hold_frames)
0871 break;
0872
0873
0874 spin_lock_irqsave(&efc->pend_frames_lock, flags);
0875
0876 if (!list_empty(&efc->pend_frames)) {
0877 seq = list_first_entry(&efc->pend_frames,
0878 struct efc_hw_sequence, list_entry);
0879 list_del(&seq->list_entry);
0880 }
0881
0882 if (!seq) {
0883 processed = efc->pend_frames_processed;
0884 efc->pend_frames_processed = 0;
0885 spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
0886 break;
0887 }
0888 efc->pend_frames_processed++;
0889
0890 spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
0891
0892
0893 if (efc_domain_dispatch_frame(domain, seq))
0894 efc->tt.hw_seq_free(efc, seq);
0895
0896 seq = NULL;
0897 }
0898
0899 if (processed != 0)
0900 efc_log_debug(efc, "%u domain frames held and processed\n",
0901 processed);
0902 }
0903
0904 void
0905 efc_dispatch_frame(struct efc *efc, struct efc_hw_sequence *seq)
0906 {
0907 struct efc_domain *domain = efc->domain;
0908
0909
0910
0911
0912
0913
0914 if (!domain || efc->hold_frames || !list_empty(&efc->pend_frames)) {
0915 unsigned long flags = 0;
0916
0917 spin_lock_irqsave(&efc->pend_frames_lock, flags);
0918 INIT_LIST_HEAD(&seq->list_entry);
0919 list_add_tail(&seq->list_entry, &efc->pend_frames);
0920 spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
0921
0922 if (domain) {
0923
0924 efct_domain_process_pending(domain);
0925 }
0926 } else {
0927
0928
0929
0930
0931
0932 if (efc_domain_dispatch_frame(domain, seq))
0933 efc->tt.hw_seq_free(efc, seq);
0934 }
0935 }
0936
0937 int
0938 efc_domain_dispatch_frame(void *arg, struct efc_hw_sequence *seq)
0939 {
0940 struct efc_domain *domain = (struct efc_domain *)arg;
0941 struct efc *efc = domain->efc;
0942 struct fc_frame_header *hdr;
0943 struct efc_node *node = NULL;
0944 struct efc_nport *nport = NULL;
0945 unsigned long flags = 0;
0946 u32 s_id, d_id, rc = EFC_HW_SEQ_FREE;
0947
0948 if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) {
0949 efc_log_err(efc, "Sequence header or payload is null\n");
0950 return rc;
0951 }
0952
0953 hdr = seq->header->dma.virt;
0954
0955
0956 s_id = ntoh24(hdr->fh_s_id);
0957 d_id = ntoh24(hdr->fh_d_id);
0958
0959 spin_lock_irqsave(&efc->lock, flags);
0960
0961 nport = efc_nport_find(domain, d_id);
0962 if (!nport) {
0963 if (hdr->fh_type == FC_TYPE_FCP) {
0964
0965 efc_log_warn(efc, "FCP frame with invalid d_id x%x\n",
0966 d_id);
0967 goto out;
0968 }
0969
0970
0971 nport = domain->nport;
0972 if (!nport || !kref_get_unless_zero(&nport->ref)) {
0973 efc_log_err(efc, "Physical nport is NULL\n");
0974 goto out;
0975 }
0976 }
0977
0978
0979 node = efc_node_find(nport, s_id);
0980
0981
0982 if (!node) {
0983
0984
0985
0986
0987 if ((hdr->fh_r_ctl == FC_RCTL_DD_SOL_DATA) ||
0988 (hdr->fh_r_ctl == FC_RCTL_DD_SOL_CTL)) {
0989 efc_log_debug(efc, "sol data/ctrl frame without node\n");
0990 goto out_release;
0991 }
0992
0993 node = efc_node_alloc(nport, s_id, false, false);
0994 if (!node) {
0995 efc_log_err(efc, "efc_node_alloc() failed\n");
0996 goto out_release;
0997 }
0998
0999 efc_node_init_device(node, false);
1000 }
1001
1002 if (node->hold_frames || !list_empty(&node->pend_frames)) {
1003
1004 spin_lock(&node->pend_frames_lock);
1005 INIT_LIST_HEAD(&seq->list_entry);
1006 list_add_tail(&seq->list_entry, &node->pend_frames);
1007 spin_unlock(&node->pend_frames_lock);
1008 rc = EFC_HW_SEQ_HOLD;
1009 goto out_release;
1010 }
1011
1012
1013 efc_node_dispatch_frame(node, seq);
1014
1015 out_release:
1016 kref_put(&nport->ref, nport->release);
1017 out:
1018 spin_unlock_irqrestore(&efc->lock, flags);
1019 return rc;
1020 }
1021
1022 void
1023 efc_node_dispatch_frame(void *arg, struct efc_hw_sequence *seq)
1024 {
1025 struct fc_frame_header *hdr = seq->header->dma.virt;
1026 u32 port_id;
1027 struct efc_node *node = (struct efc_node *)arg;
1028 struct efc *efc = node->efc;
1029
1030 port_id = ntoh24(hdr->fh_s_id);
1031
1032 if (WARN_ON(port_id != node->rnode.fc_id))
1033 return;
1034
1035 if ((!(ntoh24(hdr->fh_f_ctl) & FC_FC_END_SEQ)) ||
1036 !(ntoh24(hdr->fh_f_ctl) & FC_FC_SEQ_INIT)) {
1037 node_printf(node,
1038 "Drop frame hdr = %08x %08x %08x %08x %08x %08x\n",
1039 cpu_to_be32(((u32 *)hdr)[0]),
1040 cpu_to_be32(((u32 *)hdr)[1]),
1041 cpu_to_be32(((u32 *)hdr)[2]),
1042 cpu_to_be32(((u32 *)hdr)[3]),
1043 cpu_to_be32(((u32 *)hdr)[4]),
1044 cpu_to_be32(((u32 *)hdr)[5]));
1045 return;
1046 }
1047
1048 switch (hdr->fh_r_ctl) {
1049 case FC_RCTL_ELS_REQ:
1050 case FC_RCTL_ELS_REP:
1051 efc_node_recv_els_frame(node, seq);
1052 break;
1053
1054 case FC_RCTL_BA_ABTS:
1055 case FC_RCTL_BA_ACC:
1056 case FC_RCTL_BA_RJT:
1057 case FC_RCTL_BA_NOP:
1058 efc_log_err(efc, "Received ABTS:\n");
1059 break;
1060
1061 case FC_RCTL_DD_UNSOL_CMD:
1062 case FC_RCTL_DD_UNSOL_CTL:
1063 switch (hdr->fh_type) {
1064 case FC_TYPE_FCP:
1065 if ((hdr->fh_r_ctl & 0xf) == FC_RCTL_DD_UNSOL_CMD) {
1066 if (!node->fcp_enabled) {
1067 efc_node_recv_fcp_cmd(node, seq);
1068 break;
1069 }
1070 efc_log_err(efc, "Recvd FCP CMD. Drop IO\n");
1071 } else if ((hdr->fh_r_ctl & 0xf) ==
1072 FC_RCTL_DD_SOL_DATA) {
1073 node_printf(node,
1074 "solicited data recvd. Drop IO\n");
1075 }
1076 break;
1077
1078 case FC_TYPE_CT:
1079 efc_node_recv_ct_frame(node, seq);
1080 break;
1081 default:
1082 break;
1083 }
1084 break;
1085 default:
1086 efc_log_err(efc, "Unhandled frame rctl: %02x\n", hdr->fh_r_ctl);
1087 }
1088 }