bfa_fcs_fcpim.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*
  2. * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
  3. * All rights reserved
  4. * www.brocade.com
  5. *
  6. * Linux driver for Brocade Fibre Channel Host Bus Adapter.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License (GPL) Version 2 as
  10. * published by the Free Software Foundation
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. */
  17. /*
  18. * fcpim.c - FCP initiator mode i-t nexus state machine
  19. */
  20. #include "bfad_drv.h"
  21. #include "bfa_fcs.h"
  22. #include "bfa_fcbuild.h"
  23. #include "bfad_im.h"
  24. BFA_TRC_FILE(FCS, FCPIM);
  25. /*
  26. * forward declarations
  27. */
  28. static void bfa_fcs_itnim_timeout(void *arg);
  29. static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
  30. static void bfa_fcs_itnim_send_prli(void *itnim_cbarg,
  31. struct bfa_fcxp_s *fcxp_alloced);
  32. static void bfa_fcs_itnim_prli_response(void *fcsarg,
  33. struct bfa_fcxp_s *fcxp, void *cbarg,
  34. bfa_status_t req_status, u32 rsp_len,
  35. u32 resid_len, struct fchs_s *rsp_fchs);
  36. static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
  37. enum bfa_itnim_aen_event event);
  38. static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
  39. enum bfa_fcs_itnim_event event);
  40. static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
  41. enum bfa_fcs_itnim_event event);
  42. static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
  43. enum bfa_fcs_itnim_event event);
  44. static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
  45. enum bfa_fcs_itnim_event event);
  46. static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
  47. enum bfa_fcs_itnim_event event);
  48. static void bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
  49. enum bfa_fcs_itnim_event event);
  50. static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
  51. enum bfa_fcs_itnim_event event);
  52. static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
  53. enum bfa_fcs_itnim_event event);
  54. static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
  55. enum bfa_fcs_itnim_event event);
  56. static struct bfa_sm_table_s itnim_sm_table[] = {
  57. {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
  58. {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
  59. {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
  60. {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
  61. {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
  62. {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
  63. {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
  64. {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
  65. };
  66. /*
  67. * fcs_itnim_sm FCS itnim state machine
  68. */
  69. static void
  70. bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
  71. enum bfa_fcs_itnim_event event)
  72. {
  73. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  74. bfa_trc(itnim->fcs, event);
  75. switch (event) {
  76. case BFA_FCS_ITNIM_SM_FCS_ONLINE:
  77. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
  78. itnim->prli_retries = 0;
  79. bfa_fcs_itnim_send_prli(itnim, NULL);
  80. break;
  81. case BFA_FCS_ITNIM_SM_OFFLINE:
  82. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  83. break;
  84. case BFA_FCS_ITNIM_SM_INITIATOR:
  85. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
  86. break;
  87. case BFA_FCS_ITNIM_SM_DELETE:
  88. bfa_fcs_itnim_free(itnim);
  89. break;
  90. default:
  91. bfa_sm_fault(itnim->fcs, event);
  92. }
  93. }
  94. static void
  95. bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
  96. enum bfa_fcs_itnim_event event)
  97. {
  98. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  99. bfa_trc(itnim->fcs, event);
  100. switch (event) {
  101. case BFA_FCS_ITNIM_SM_FRMSENT:
  102. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
  103. break;
  104. case BFA_FCS_ITNIM_SM_INITIATOR:
  105. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
  106. bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
  107. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
  108. break;
  109. case BFA_FCS_ITNIM_SM_OFFLINE:
  110. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  111. bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
  112. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  113. break;
  114. case BFA_FCS_ITNIM_SM_DELETE:
  115. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  116. bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
  117. bfa_fcs_itnim_free(itnim);
  118. break;
  119. default:
  120. bfa_sm_fault(itnim->fcs, event);
  121. }
  122. }
  123. static void
  124. bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
  125. enum bfa_fcs_itnim_event event)
  126. {
  127. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  128. bfa_trc(itnim->fcs, event);
  129. switch (event) {
  130. case BFA_FCS_ITNIM_SM_RSP_OK:
  131. if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR)
  132. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
  133. else
  134. bfa_sm_set_state(itnim,
  135. bfa_fcs_itnim_sm_hal_rport_online);
  136. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
  137. break;
  138. case BFA_FCS_ITNIM_SM_RSP_ERROR:
  139. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
  140. bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
  141. bfa_fcs_itnim_timeout, itnim,
  142. BFA_FCS_RETRY_TIMEOUT);
  143. break;
  144. case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP:
  145. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  146. break;
  147. case BFA_FCS_ITNIM_SM_OFFLINE:
  148. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  149. bfa_fcxp_discard(itnim->fcxp);
  150. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  151. break;
  152. case BFA_FCS_ITNIM_SM_INITIATOR:
  153. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
  154. bfa_fcxp_discard(itnim->fcxp);
  155. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
  156. break;
  157. case BFA_FCS_ITNIM_SM_DELETE:
  158. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  159. bfa_fcxp_discard(itnim->fcxp);
  160. bfa_fcs_itnim_free(itnim);
  161. break;
  162. default:
  163. bfa_sm_fault(itnim->fcs, event);
  164. }
  165. }
  166. static void
  167. bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
  168. enum bfa_fcs_itnim_event event)
  169. {
  170. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  171. bfa_trc(itnim->fcs, event);
  172. switch (event) {
  173. case BFA_FCS_ITNIM_SM_HAL_ONLINE:
  174. if (!itnim->bfa_itnim)
  175. itnim->bfa_itnim = bfa_itnim_create(itnim->fcs->bfa,
  176. itnim->rport->bfa_rport, itnim);
  177. if (itnim->bfa_itnim) {
  178. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
  179. bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
  180. } else {
  181. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  182. bfa_sm_send_event(itnim->rport, RPSM_EVENT_DELETE);
  183. }
  184. break;
  185. case BFA_FCS_ITNIM_SM_OFFLINE:
  186. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  187. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  188. break;
  189. case BFA_FCS_ITNIM_SM_DELETE:
  190. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  191. bfa_fcs_itnim_free(itnim);
  192. break;
  193. default:
  194. bfa_sm_fault(itnim->fcs, event);
  195. }
  196. }
  197. static void
  198. bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
  199. enum bfa_fcs_itnim_event event)
  200. {
  201. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  202. bfa_trc(itnim->fcs, event);
  203. switch (event) {
  204. case BFA_FCS_ITNIM_SM_TIMEOUT:
  205. if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
  206. itnim->prli_retries++;
  207. bfa_trc(itnim->fcs, itnim->prli_retries);
  208. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
  209. bfa_fcs_itnim_send_prli(itnim, NULL);
  210. } else {
  211. /* invoke target offline */
  212. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  213. bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
  214. }
  215. break;
  216. case BFA_FCS_ITNIM_SM_OFFLINE:
  217. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  218. bfa_timer_stop(&itnim->timer);
  219. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  220. break;
  221. case BFA_FCS_ITNIM_SM_INITIATOR:
  222. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
  223. bfa_timer_stop(&itnim->timer);
  224. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
  225. break;
  226. case BFA_FCS_ITNIM_SM_DELETE:
  227. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  228. bfa_timer_stop(&itnim->timer);
  229. bfa_fcs_itnim_free(itnim);
  230. break;
  231. default:
  232. bfa_sm_fault(itnim->fcs, event);
  233. }
  234. }
  235. static void
  236. bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
  237. enum bfa_fcs_itnim_event event)
  238. {
  239. struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
  240. char lpwwn_buf[BFA_STRING_32];
  241. char rpwwn_buf[BFA_STRING_32];
  242. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  243. bfa_trc(itnim->fcs, event);
  244. switch (event) {
  245. case BFA_FCS_ITNIM_SM_HCB_ONLINE:
  246. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
  247. bfa_fcb_itnim_online(itnim->itnim_drv);
  248. wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
  249. wwn2str(rpwwn_buf, itnim->rport->pwwn);
  250. BFA_LOG(KERN_INFO, bfad, bfa_log_level,
  251. "Target (WWN = %s) is online for initiator (WWN = %s)\n",
  252. rpwwn_buf, lpwwn_buf);
  253. bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
  254. break;
  255. case BFA_FCS_ITNIM_SM_OFFLINE:
  256. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
  257. bfa_itnim_offline(itnim->bfa_itnim);
  258. break;
  259. case BFA_FCS_ITNIM_SM_DELETE:
  260. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  261. bfa_fcs_itnim_free(itnim);
  262. break;
  263. default:
  264. bfa_sm_fault(itnim->fcs, event);
  265. }
  266. }
  267. static void
  268. bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
  269. enum bfa_fcs_itnim_event event)
  270. {
  271. struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
  272. char lpwwn_buf[BFA_STRING_32];
  273. char rpwwn_buf[BFA_STRING_32];
  274. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  275. bfa_trc(itnim->fcs, event);
  276. switch (event) {
  277. case BFA_FCS_ITNIM_SM_OFFLINE:
  278. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
  279. bfa_fcb_itnim_offline(itnim->itnim_drv);
  280. bfa_itnim_offline(itnim->bfa_itnim);
  281. wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
  282. wwn2str(rpwwn_buf, itnim->rport->pwwn);
  283. if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
  284. BFA_LOG(KERN_ERR, bfad, bfa_log_level,
  285. "Target (WWN = %s) connectivity lost for "
  286. "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
  287. bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
  288. } else {
  289. BFA_LOG(KERN_INFO, bfad, bfa_log_level,
  290. "Target (WWN = %s) offlined by initiator (WWN = %s)\n",
  291. rpwwn_buf, lpwwn_buf);
  292. bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
  293. }
  294. break;
  295. case BFA_FCS_ITNIM_SM_DELETE:
  296. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  297. bfa_fcs_itnim_free(itnim);
  298. break;
  299. default:
  300. bfa_sm_fault(itnim->fcs, event);
  301. }
  302. }
  303. static void
  304. bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
  305. enum bfa_fcs_itnim_event event)
  306. {
  307. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  308. bfa_trc(itnim->fcs, event);
  309. switch (event) {
  310. case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
  311. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  312. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  313. break;
  314. case BFA_FCS_ITNIM_SM_DELETE:
  315. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  316. bfa_fcs_itnim_free(itnim);
  317. break;
  318. default:
  319. bfa_sm_fault(itnim->fcs, event);
  320. }
  321. }
  322. /*
  323. * This state is set when a discovered rport is also in intiator mode.
  324. * This ITN is marked as no_op and is not active and will not be truned into
  325. * online state.
  326. */
  327. static void
  328. bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
  329. enum bfa_fcs_itnim_event event)
  330. {
  331. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  332. bfa_trc(itnim->fcs, event);
  333. switch (event) {
  334. case BFA_FCS_ITNIM_SM_OFFLINE:
  335. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  336. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
  337. break;
  338. /*
  339. * fcs_online is expected here for well known initiator ports
  340. */
  341. case BFA_FCS_ITNIM_SM_FCS_ONLINE:
  342. bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
  343. break;
  344. case BFA_FCS_ITNIM_SM_RSP_ERROR:
  345. case BFA_FCS_ITNIM_SM_INITIATOR:
  346. break;
  347. case BFA_FCS_ITNIM_SM_DELETE:
  348. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  349. bfa_fcs_itnim_free(itnim);
  350. break;
  351. default:
  352. bfa_sm_fault(itnim->fcs, event);
  353. }
  354. }
  355. static void
  356. bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
  357. enum bfa_itnim_aen_event event)
  358. {
  359. struct bfa_fcs_rport_s *rport = itnim->rport;
  360. struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
  361. struct bfa_aen_entry_s *aen_entry;
  362. /* Don't post events for well known addresses */
  363. if (BFA_FCS_PID_IS_WKA(rport->pid))
  364. return;
  365. bfad_get_aen_entry(bfad, aen_entry);
  366. if (!aen_entry)
  367. return;
  368. aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
  369. aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
  370. bfa_fcs_get_base_port(itnim->fcs));
  371. aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
  372. aen_entry->aen_data.itnim.rpwwn = rport->pwwn;
  373. /* Send the AEN notification */
  374. bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
  375. BFA_AEN_CAT_ITNIM, event);
  376. }
  377. static void
  378. bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
  379. {
  380. struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
  381. struct bfa_fcs_rport_s *rport = itnim->rport;
  382. struct bfa_fcs_lport_s *port = rport->port;
  383. struct fchs_s fchs;
  384. struct bfa_fcxp_s *fcxp;
  385. int len;
  386. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  387. fcxp = fcxp_alloced ? fcxp_alloced :
  388. bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
  389. if (!fcxp) {
  390. itnim->stats.fcxp_alloc_wait++;
  391. bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
  392. bfa_fcs_itnim_send_prli, itnim, BFA_TRUE);
  393. return;
  394. }
  395. itnim->fcxp = fcxp;
  396. len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
  397. itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
  398. bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
  399. BFA_FALSE, FC_CLASS_3, len, &fchs,
  400. bfa_fcs_itnim_prli_response, (void *)itnim,
  401. FC_MAX_PDUSZ, FC_ELS_TOV);
  402. itnim->stats.prli_sent++;
  403. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
  404. }
  405. static void
  406. bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
  407. bfa_status_t req_status, u32 rsp_len,
  408. u32 resid_len, struct fchs_s *rsp_fchs)
  409. {
  410. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
  411. struct fc_els_cmd_s *els_cmd;
  412. struct fc_prli_s *prli_resp;
  413. struct fc_ls_rjt_s *ls_rjt;
  414. struct fc_prli_params_s *sparams;
  415. bfa_trc(itnim->fcs, req_status);
  416. /*
  417. * Sanity Checks
  418. */
  419. if (req_status != BFA_STATUS_OK) {
  420. itnim->stats.prli_rsp_err++;
  421. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
  422. return;
  423. }
  424. els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
  425. if (els_cmd->els_code == FC_ELS_ACC) {
  426. prli_resp = (struct fc_prli_s *) els_cmd;
  427. if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
  428. bfa_trc(itnim->fcs, rsp_len);
  429. /*
  430. * Check if this r-port is also in Initiator mode.
  431. * If so, we need to set this ITN as a no-op.
  432. */
  433. if (prli_resp->parampage.servparams.initiator) {
  434. bfa_trc(itnim->fcs, prli_resp->parampage.type);
  435. itnim->rport->scsi_function =
  436. BFA_RPORT_INITIATOR;
  437. itnim->stats.prli_rsp_acc++;
  438. itnim->stats.initiator++;
  439. bfa_sm_send_event(itnim,
  440. BFA_FCS_ITNIM_SM_RSP_OK);
  441. return;
  442. }
  443. itnim->stats.prli_rsp_parse_err++;
  444. return;
  445. }
  446. itnim->rport->scsi_function = BFA_RPORT_TARGET;
  447. sparams = &prli_resp->parampage.servparams;
  448. itnim->seq_rec = sparams->retry;
  449. itnim->rec_support = sparams->rec_support;
  450. itnim->task_retry_id = sparams->task_retry_id;
  451. itnim->conf_comp = sparams->confirm;
  452. itnim->stats.prli_rsp_acc++;
  453. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
  454. } else {
  455. ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
  456. bfa_trc(itnim->fcs, ls_rjt->reason_code);
  457. bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
  458. itnim->stats.prli_rsp_rjt++;
  459. if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
  460. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP);
  461. return;
  462. }
  463. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
  464. }
  465. }
  466. static void
  467. bfa_fcs_itnim_timeout(void *arg)
  468. {
  469. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
  470. itnim->stats.timeout++;
  471. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
  472. }
  473. static void
  474. bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
  475. {
  476. if (itnim->bfa_itnim) {
  477. bfa_itnim_delete(itnim->bfa_itnim);
  478. itnim->bfa_itnim = NULL;
  479. }
  480. bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
  481. }
  482. /*
  483. * itnim_public FCS ITNIM public interfaces
  484. */
  485. /*
  486. * Called by rport when a new rport is created.
  487. *
  488. * @param[in] rport - remote port.
  489. */
  490. struct bfa_fcs_itnim_s *
  491. bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
  492. {
  493. struct bfa_fcs_lport_s *port = rport->port;
  494. struct bfa_fcs_itnim_s *itnim;
  495. struct bfad_itnim_s *itnim_drv;
  496. /*
  497. * call bfad to allocate the itnim
  498. */
  499. bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
  500. if (itnim == NULL) {
  501. bfa_trc(port->fcs, rport->pwwn);
  502. return NULL;
  503. }
  504. /*
  505. * Initialize itnim
  506. */
  507. itnim->rport = rport;
  508. itnim->fcs = rport->fcs;
  509. itnim->itnim_drv = itnim_drv;
  510. itnim->bfa_itnim = NULL;
  511. itnim->seq_rec = BFA_FALSE;
  512. itnim->rec_support = BFA_FALSE;
  513. itnim->conf_comp = BFA_FALSE;
  514. itnim->task_retry_id = BFA_FALSE;
  515. /*
  516. * Set State machine
  517. */
  518. bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
  519. return itnim;
  520. }
  521. /*
  522. * Called by rport to delete the instance of FCPIM.
  523. *
  524. * @param[in] rport - remote port.
  525. */
  526. void
  527. bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
  528. {
  529. bfa_trc(itnim->fcs, itnim->rport->pid);
  530. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
  531. }
  532. /*
  533. * Notification from rport that PLOGI is complete to initiate FC-4 session.
  534. */
  535. void
  536. bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim)
  537. {
  538. itnim->stats.onlines++;
  539. if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid))
  540. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE);
  541. }
  542. /*
  543. * Called by rport to handle a remote device offline.
  544. */
  545. void
  546. bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
  547. {
  548. itnim->stats.offlines++;
  549. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
  550. }
  551. /*
  552. * Called by rport when remote port is known to be an initiator from
  553. * PRLI received.
  554. */
  555. void
  556. bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
  557. {
  558. bfa_trc(itnim->fcs, itnim->rport->pid);
  559. itnim->stats.initiator++;
  560. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
  561. }
  562. /*
  563. * Called by rport to check if the itnim is online.
  564. */
  565. bfa_status_t
  566. bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
  567. {
  568. bfa_trc(itnim->fcs, itnim->rport->pid);
  569. switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
  570. case BFA_ITNIM_ONLINE:
  571. case BFA_ITNIM_INITIATIOR:
  572. return BFA_STATUS_OK;
  573. default:
  574. return BFA_STATUS_NO_FCPIM_NEXUS;
  575. }
  576. }
  577. /*
  578. * BFA completion callback for bfa_itnim_online().
  579. */
  580. void
  581. bfa_cb_itnim_online(void *cbarg)
  582. {
  583. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
  584. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  585. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
  586. }
  587. /*
  588. * BFA completion callback for bfa_itnim_offline().
  589. */
  590. void
  591. bfa_cb_itnim_offline(void *cb_arg)
  592. {
  593. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
  594. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  595. bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
  596. }
  597. /*
  598. * Mark the beginning of PATH TOV handling. IO completion callbacks
  599. * are still pending.
  600. */
  601. void
  602. bfa_cb_itnim_tov_begin(void *cb_arg)
  603. {
  604. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
  605. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  606. }
  607. /*
  608. * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
  609. */
  610. void
  611. bfa_cb_itnim_tov(void *cb_arg)
  612. {
  613. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
  614. struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
  615. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  616. itnim_drv->state = ITNIM_STATE_TIMEOUT;
  617. }
  618. /*
  619. * BFA notification to FCS/driver for second level error recovery.
  620. *
  621. * Atleast one I/O request has timedout and target is unresponsive to
  622. * repeated abort requests. Second level error recovery should be initiated
  623. * by starting implicit logout and recovery procedures.
  624. */
  625. void
  626. bfa_cb_itnim_sler(void *cb_arg)
  627. {
  628. struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
  629. itnim->stats.sler++;
  630. bfa_trc(itnim->fcs, itnim->rport->pwwn);
  631. bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
  632. }
  633. struct bfa_fcs_itnim_s *
  634. bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
  635. {
  636. struct bfa_fcs_rport_s *rport;
  637. rport = bfa_fcs_rport_lookup(port, rpwwn);
  638. if (!rport)
  639. return NULL;
  640. WARN_ON(rport->itnim == NULL);
  641. return rport->itnim;
  642. }
  643. bfa_status_t
  644. bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
  645. struct bfa_itnim_attr_s *attr)
  646. {
  647. struct bfa_fcs_itnim_s *itnim = NULL;
  648. itnim = bfa_fcs_itnim_lookup(port, rpwwn);
  649. if (itnim == NULL)
  650. return BFA_STATUS_NO_FCPIM_NEXUS;
  651. attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm);
  652. attr->retry = itnim->seq_rec;
  653. attr->rec_support = itnim->rec_support;
  654. attr->conf_comp = itnim->conf_comp;
  655. attr->task_retry_id = itnim->task_retry_id;
  656. return BFA_STATUS_OK;
  657. }
  658. bfa_status_t
  659. bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
  660. struct bfa_itnim_stats_s *stats)
  661. {
  662. struct bfa_fcs_itnim_s *itnim = NULL;
  663. WARN_ON(port == NULL);
  664. itnim = bfa_fcs_itnim_lookup(port, rpwwn);
  665. if (itnim == NULL)
  666. return BFA_STATUS_NO_FCPIM_NEXUS;
  667. memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
  668. return BFA_STATUS_OK;
  669. }
  670. bfa_status_t
  671. bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
  672. {
  673. struct bfa_fcs_itnim_s *itnim = NULL;
  674. WARN_ON(port == NULL);
  675. itnim = bfa_fcs_itnim_lookup(port, rpwwn);
  676. if (itnim == NULL)
  677. return BFA_STATUS_NO_FCPIM_NEXUS;
  678. memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
  679. return BFA_STATUS_OK;
  680. }
  681. void
  682. bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
  683. struct fchs_s *fchs, u16 len)
  684. {
  685. struct fc_els_cmd_s *els_cmd;
  686. bfa_trc(itnim->fcs, fchs->type);
  687. if (fchs->type != FC_TYPE_ELS)
  688. return;
  689. els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
  690. bfa_trc(itnim->fcs, els_cmd->els_code);
  691. switch (els_cmd->els_code) {
  692. case FC_ELS_PRLO:
  693. bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
  694. break;
  695. default:
  696. WARN_ON(1);
  697. }
  698. }