um_idi.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* $Id: um_idi.c,v 1.14 2004/03/21 17:54:37 armin Exp $ */
  3. #include "platform.h"
  4. #include "di_defs.h"
  5. #include "pc.h"
  6. #include "dqueue.h"
  7. #include "adapter.h"
  8. #include "entity.h"
  9. #include "um_xdi.h"
  10. #include "um_idi.h"
  11. #include "debuglib.h"
  12. #include "divasync.h"
  13. #define DIVAS_MAX_XDI_ADAPTERS 64
  14. /* --------------------------------------------------------------------------
  15. IMPORTS
  16. -------------------------------------------------------------------------- */
  17. extern void diva_os_wakeup_read(void *os_context);
  18. extern void diva_os_wakeup_close(void *os_context);
  19. /* --------------------------------------------------------------------------
  20. LOCALS
  21. -------------------------------------------------------------------------- */
  22. static LIST_HEAD(adapter_q);
  23. static diva_os_spin_lock_t adapter_lock;
  24. static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr);
  25. static void cleanup_adapter(diva_um_idi_adapter_t *a);
  26. static void cleanup_entity(divas_um_idi_entity_t *e);
  27. static int diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t *a,
  28. diva_um_idi_adapter_features_t
  29. *features);
  30. static int process_idi_request(divas_um_idi_entity_t *e,
  31. const diva_um_idi_req_hdr_t *req);
  32. static int process_idi_rc(divas_um_idi_entity_t *e, byte rc);
  33. static int process_idi_ind(divas_um_idi_entity_t *e, byte ind);
  34. static int write_return_code(divas_um_idi_entity_t *e, byte rc);
  35. /* --------------------------------------------------------------------------
  36. MAIN
  37. -------------------------------------------------------------------------- */
  38. int diva_user_mode_idi_init(void)
  39. {
  40. diva_os_initialize_spin_lock(&adapter_lock, "adapter");
  41. return (0);
  42. }
  43. /* --------------------------------------------------------------------------
  44. Copy adapter features to user supplied buffer
  45. -------------------------------------------------------------------------- */
  46. static int
  47. diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t *a,
  48. diva_um_idi_adapter_features_t *
  49. features)
  50. {
  51. IDI_SYNC_REQ sync_req;
  52. if ((a) && (a->d.request)) {
  53. features->type = a->d.type;
  54. features->features = a->d.features;
  55. features->channels = a->d.channels;
  56. memset(features->name, 0, sizeof(features->name));
  57. sync_req.GetName.Req = 0;
  58. sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
  59. (*(a->d.request)) ((ENTITY *)&sync_req);
  60. strlcpy(features->name, sync_req.GetName.name,
  61. sizeof(features->name));
  62. sync_req.GetSerial.Req = 0;
  63. sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
  64. sync_req.GetSerial.serial = 0;
  65. (*(a->d.request))((ENTITY *)&sync_req);
  66. features->serial_number = sync_req.GetSerial.serial;
  67. }
  68. return ((a) ? 0 : -1);
  69. }
  70. /* --------------------------------------------------------------------------
  71. REMOVE ADAPTER
  72. -------------------------------------------------------------------------- */
  73. void diva_user_mode_idi_remove_adapter(int adapter_nr)
  74. {
  75. struct list_head *tmp;
  76. diva_um_idi_adapter_t *a;
  77. list_for_each(tmp, &adapter_q) {
  78. a = list_entry(tmp, diva_um_idi_adapter_t, link);
  79. if (a->adapter_nr == adapter_nr) {
  80. list_del(tmp);
  81. cleanup_adapter(a);
  82. DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
  83. diva_os_free(0, a);
  84. break;
  85. }
  86. }
  87. }
  88. /* --------------------------------------------------------------------------
  89. CALLED ON DRIVER EXIT (UNLOAD)
  90. -------------------------------------------------------------------------- */
  91. void diva_user_mode_idi_finit(void)
  92. {
  93. struct list_head *tmp, *safe;
  94. diva_um_idi_adapter_t *a;
  95. list_for_each_safe(tmp, safe, &adapter_q) {
  96. a = list_entry(tmp, diva_um_idi_adapter_t, link);
  97. list_del(tmp);
  98. cleanup_adapter(a);
  99. DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
  100. diva_os_free(0, a);
  101. }
  102. diva_os_destroy_spin_lock(&adapter_lock, "adapter");
  103. }
  104. /* -------------------------------------------------------------------------
  105. CREATE AND INIT IDI ADAPTER
  106. ------------------------------------------------------------------------- */
  107. int diva_user_mode_idi_create_adapter(const DESCRIPTOR *d, int adapter_nr)
  108. {
  109. diva_os_spin_lock_magic_t old_irql;
  110. diva_um_idi_adapter_t *a =
  111. (diva_um_idi_adapter_t *) diva_os_malloc(0,
  112. sizeof
  113. (diva_um_idi_adapter_t));
  114. if (!a) {
  115. return (-1);
  116. }
  117. memset(a, 0x00, sizeof(*a));
  118. INIT_LIST_HEAD(&a->entity_q);
  119. a->d = *d;
  120. a->adapter_nr = adapter_nr;
  121. DBG_LOG(("DIDD_ADD A(%d), type:%02x, features:%04x, channels:%d",
  122. adapter_nr, a->d.type, a->d.features, a->d.channels));
  123. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_adapter");
  124. list_add_tail(&a->link, &adapter_q);
  125. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_adapter");
  126. return (0);
  127. }
  128. /* ------------------------------------------------------------------------
  129. Find adapter by Adapter number
  130. ------------------------------------------------------------------------ */
  131. static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr)
  132. {
  133. diva_um_idi_adapter_t *a = NULL;
  134. struct list_head *tmp;
  135. list_for_each(tmp, &adapter_q) {
  136. a = list_entry(tmp, diva_um_idi_adapter_t, link);
  137. DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
  138. if (a->adapter_nr == (int)nr)
  139. break;
  140. a = NULL;
  141. }
  142. return (a);
  143. }
  144. /* ------------------------------------------------------------------------
  145. Cleanup this adapter and cleanup/delete all entities assigned
  146. to this adapter
  147. ------------------------------------------------------------------------ */
  148. static void cleanup_adapter(diva_um_idi_adapter_t *a)
  149. {
  150. struct list_head *tmp, *safe;
  151. divas_um_idi_entity_t *e;
  152. list_for_each_safe(tmp, safe, &a->entity_q) {
  153. e = list_entry(tmp, divas_um_idi_entity_t, link);
  154. list_del(tmp);
  155. cleanup_entity(e);
  156. if (e->os_context) {
  157. diva_os_wakeup_read(e->os_context);
  158. diva_os_wakeup_close(e->os_context);
  159. }
  160. }
  161. memset(&a->d, 0x00, sizeof(DESCRIPTOR));
  162. }
  163. /* ------------------------------------------------------------------------
  164. Cleanup, but NOT delete this entity
  165. ------------------------------------------------------------------------ */
  166. static void cleanup_entity(divas_um_idi_entity_t *e)
  167. {
  168. e->os_ref = NULL;
  169. e->status = 0;
  170. e->adapter = NULL;
  171. e->e.Id = 0;
  172. e->rc_count = 0;
  173. e->status |= DIVA_UM_IDI_REMOVED;
  174. e->status |= DIVA_UM_IDI_REMOVE_PENDING;
  175. diva_data_q_finit(&e->data);
  176. diva_data_q_finit(&e->rc);
  177. }
  178. /* ------------------------------------------------------------------------
  179. Create ENTITY, link it to the adapter and remove pointer to entity
  180. ------------------------------------------------------------------------ */
  181. void *divas_um_idi_create_entity(dword adapter_nr, void *file)
  182. {
  183. divas_um_idi_entity_t *e;
  184. diva_um_idi_adapter_t *a;
  185. diva_os_spin_lock_magic_t old_irql;
  186. if ((e = (divas_um_idi_entity_t *) diva_os_malloc(0, sizeof(*e)))) {
  187. memset(e, 0x00, sizeof(*e));
  188. if (!
  189. (e->os_context =
  190. diva_os_malloc(0, diva_os_get_context_size()))) {
  191. DBG_LOG(("E(%08x) no memory for os context", e));
  192. diva_os_free(0, e);
  193. return NULL;
  194. }
  195. memset(e->os_context, 0x00, diva_os_get_context_size());
  196. if ((diva_data_q_init(&e->data, 2048 + 512, 16))) {
  197. diva_os_free(0, e->os_context);
  198. diva_os_free(0, e);
  199. return NULL;
  200. }
  201. if ((diva_data_q_init(&e->rc, sizeof(diva_um_idi_ind_hdr_t), 2))) {
  202. diva_data_q_finit(&e->data);
  203. diva_os_free(0, e->os_context);
  204. diva_os_free(0, e);
  205. return NULL;
  206. }
  207. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_entity");
  208. /*
  209. Look for Adapter requested
  210. */
  211. if (!(a = diva_um_idi_find_adapter(adapter_nr))) {
  212. /*
  213. No adapter was found, or this adapter was removed
  214. */
  215. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
  216. DBG_LOG(("A: no adapter(%ld)", adapter_nr));
  217. cleanup_entity(e);
  218. diva_os_free(0, e->os_context);
  219. diva_os_free(0, e);
  220. return NULL;
  221. }
  222. e->os_ref = file; /* link to os handle */
  223. e->adapter = a; /* link to adapter */
  224. list_add_tail(&e->link, &a->entity_q); /* link from adapter */
  225. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
  226. DBG_LOG(("A(%ld), create E(%08x)", adapter_nr, e));
  227. }
  228. return (e);
  229. }
  230. /* ------------------------------------------------------------------------
  231. Unlink entity and free memory
  232. ------------------------------------------------------------------------ */
  233. int divas_um_idi_delete_entity(int adapter_nr, void *entity)
  234. {
  235. divas_um_idi_entity_t *e;
  236. diva_um_idi_adapter_t *a;
  237. diva_os_spin_lock_magic_t old_irql;
  238. if (!(e = (divas_um_idi_entity_t *) entity))
  239. return (-1);
  240. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "delete_entity");
  241. if ((a = e->adapter)) {
  242. list_del(&e->link);
  243. }
  244. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "delete_entity");
  245. diva_um_idi_stop_wdog(entity);
  246. cleanup_entity(e);
  247. diva_os_free(0, e->os_context);
  248. memset(e, 0x00, sizeof(*e));
  249. DBG_LOG(("A(%d) remove E:%08x", adapter_nr, e));
  250. diva_os_free(0, e);
  251. return (0);
  252. }
  253. /* --------------------------------------------------------------------------
  254. Called by application to read data from IDI
  255. -------------------------------------------------------------------------- */
  256. int diva_um_idi_read(void *entity,
  257. void *os_handle,
  258. void *dst,
  259. int max_length, divas_um_idi_copy_to_user_fn_t cp_fn)
  260. {
  261. divas_um_idi_entity_t *e;
  262. diva_um_idi_adapter_t *a;
  263. const void *data;
  264. int length, ret = 0;
  265. diva_um_idi_data_queue_t *q;
  266. diva_os_spin_lock_magic_t old_irql;
  267. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "read");
  268. e = (divas_um_idi_entity_t *) entity;
  269. if (!e || (!(a = e->adapter)) ||
  270. (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
  271. (e->status & DIVA_UM_IDI_REMOVED) ||
  272. (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
  273. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
  274. DBG_ERR(("E(%08x) read failed - adapter removed", e))
  275. return (-1);
  276. }
  277. DBG_TRC(("A(%d) E(%08x) read(%d)", a->adapter_nr, e, max_length));
  278. /*
  279. Try to read return code first
  280. */
  281. data = diva_data_q_get_segment4read(&e->rc);
  282. q = &e->rc;
  283. /*
  284. No return codes available, read indications now
  285. */
  286. if (!data) {
  287. if (!(e->status & DIVA_UM_IDI_RC_PENDING)) {
  288. DBG_TRC(("A(%d) E(%08x) read data", a->adapter_nr, e));
  289. data = diva_data_q_get_segment4read(&e->data);
  290. q = &e->data;
  291. }
  292. } else {
  293. e->status &= ~DIVA_UM_IDI_RC_PENDING;
  294. DBG_TRC(("A(%d) E(%08x) read rc", a->adapter_nr, e));
  295. }
  296. if (data) {
  297. if ((length = diva_data_q_get_segment_length(q)) >
  298. max_length) {
  299. /*
  300. Not enough space to read message
  301. */
  302. DBG_ERR(("A: A(%d) E(%08x) read small buffer",
  303. a->adapter_nr, e, ret));
  304. diva_os_leave_spin_lock(&adapter_lock, &old_irql,
  305. "read");
  306. return (-2);
  307. }
  308. /*
  309. Copy it to user, this function does access ONLY locked an verified
  310. memory, also we can access it witch spin lock held
  311. */
  312. if ((ret = (*cp_fn) (os_handle, dst, data, length)) >= 0) {
  313. /*
  314. Acknowledge only if read was successful
  315. */
  316. diva_data_q_ack_segment4read(q);
  317. }
  318. }
  319. DBG_TRC(("A(%d) E(%08x) read=%d", a->adapter_nr, e, ret));
  320. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
  321. return (ret);
  322. }
  323. int diva_um_idi_write(void *entity,
  324. void *os_handle,
  325. const void *src,
  326. int length, divas_um_idi_copy_from_user_fn_t cp_fn)
  327. {
  328. divas_um_idi_entity_t *e;
  329. diva_um_idi_adapter_t *a;
  330. diva_um_idi_req_hdr_t *req;
  331. void *data;
  332. int ret = 0;
  333. diva_os_spin_lock_magic_t old_irql;
  334. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "write");
  335. e = (divas_um_idi_entity_t *) entity;
  336. if (!e || (!(a = e->adapter)) ||
  337. (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
  338. (e->status & DIVA_UM_IDI_REMOVED) ||
  339. (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
  340. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  341. DBG_ERR(("E(%08x) write failed - adapter removed", e))
  342. return (-1);
  343. }
  344. DBG_TRC(("A(%d) E(%08x) write(%d)", a->adapter_nr, e, length));
  345. if ((length < sizeof(*req)) || (length > sizeof(e->buffer))) {
  346. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  347. return (-2);
  348. }
  349. if (e->status & DIVA_UM_IDI_RC_PENDING) {
  350. DBG_ERR(("A: A(%d) E(%08x) rc pending", a->adapter_nr, e));
  351. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  352. return (-1); /* should wait for RC code first */
  353. }
  354. /*
  355. Copy function does access only locked verified memory,
  356. also it can be called with spin lock held
  357. */
  358. if ((ret = (*cp_fn) (os_handle, e->buffer, src, length)) < 0) {
  359. DBG_TRC(("A: A(%d) E(%08x) write error=%d", a->adapter_nr,
  360. e, ret));
  361. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  362. return (ret);
  363. }
  364. req = (diva_um_idi_req_hdr_t *)&e->buffer[0];
  365. switch (req->type) {
  366. case DIVA_UM_IDI_GET_FEATURES:{
  367. DBG_LOG(("A(%d) get_features", a->adapter_nr));
  368. if (!(data =
  369. diva_data_q_get_segment4write(&e->data))) {
  370. DBG_ERR(("A(%d) get_features, no free buffer",
  371. a->adapter_nr));
  372. diva_os_leave_spin_lock(&adapter_lock,
  373. &old_irql,
  374. "write");
  375. return (0);
  376. }
  377. diva_user_mode_idi_adapter_features(a, &(((diva_um_idi_ind_hdr_t
  378. *) data)->hdr.features));
  379. ((diva_um_idi_ind_hdr_t *) data)->type =
  380. DIVA_UM_IDI_IND_FEATURES;
  381. ((diva_um_idi_ind_hdr_t *) data)->data_length = 0;
  382. diva_data_q_ack_segment4write(&e->data,
  383. sizeof(diva_um_idi_ind_hdr_t));
  384. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  385. diva_os_wakeup_read(e->os_context);
  386. }
  387. break;
  388. case DIVA_UM_IDI_REQ:
  389. case DIVA_UM_IDI_REQ_MAN:
  390. case DIVA_UM_IDI_REQ_SIG:
  391. case DIVA_UM_IDI_REQ_NET:
  392. DBG_TRC(("A(%d) REQ(%02d)-(%02d)-(%08x)", a->adapter_nr,
  393. req->Req, req->ReqCh,
  394. req->type & DIVA_UM_IDI_REQ_TYPE_MASK));
  395. switch (process_idi_request(e, req)) {
  396. case -1:
  397. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  398. return (-1);
  399. case -2:
  400. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  401. diva_os_wakeup_read(e->os_context);
  402. break;
  403. default:
  404. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  405. break;
  406. }
  407. break;
  408. default:
  409. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
  410. return (-1);
  411. }
  412. DBG_TRC(("A(%d) E(%08x) write=%d", a->adapter_nr, e, ret));
  413. return (ret);
  414. }
  415. /* --------------------------------------------------------------------------
  416. CALLBACK FROM XDI
  417. -------------------------------------------------------------------------- */
  418. static void diva_um_idi_xdi_callback(ENTITY *entity)
  419. {
  420. divas_um_idi_entity_t *e = DIVAS_CONTAINING_RECORD(entity,
  421. divas_um_idi_entity_t,
  422. e);
  423. diva_os_spin_lock_magic_t old_irql;
  424. int call_wakeup = 0;
  425. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
  426. if (e->e.complete == 255) {
  427. if (!(e->status & DIVA_UM_IDI_REMOVE_PENDING)) {
  428. diva_um_idi_stop_wdog(e);
  429. }
  430. if ((call_wakeup = process_idi_rc(e, e->e.Rc))) {
  431. if (e->rc_count) {
  432. e->rc_count--;
  433. }
  434. }
  435. e->e.Rc = 0;
  436. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
  437. if (call_wakeup) {
  438. diva_os_wakeup_read(e->os_context);
  439. diva_os_wakeup_close(e->os_context);
  440. }
  441. } else {
  442. if (e->status & DIVA_UM_IDI_REMOVE_PENDING) {
  443. e->e.RNum = 0;
  444. e->e.RNR = 2;
  445. } else {
  446. call_wakeup = process_idi_ind(e, e->e.Ind);
  447. }
  448. e->e.Ind = 0;
  449. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
  450. if (call_wakeup) {
  451. diva_os_wakeup_read(e->os_context);
  452. }
  453. }
  454. }
  455. static int process_idi_request(divas_um_idi_entity_t *e,
  456. const diva_um_idi_req_hdr_t *req)
  457. {
  458. int assign = 0;
  459. byte Req = (byte) req->Req;
  460. dword type = req->type & DIVA_UM_IDI_REQ_TYPE_MASK;
  461. if (!e->e.Id || !e->e.callback) { /* not assigned */
  462. if (Req != ASSIGN) {
  463. DBG_ERR(("A: A(%d) E(%08x) not assigned",
  464. e->adapter->adapter_nr, e));
  465. return (-1); /* NOT ASSIGNED */
  466. } else {
  467. switch (type) {
  468. case DIVA_UM_IDI_REQ_TYPE_MAN:
  469. e->e.Id = MAN_ID;
  470. DBG_TRC(("A(%d) E(%08x) assign MAN",
  471. e->adapter->adapter_nr, e));
  472. break;
  473. case DIVA_UM_IDI_REQ_TYPE_SIG:
  474. e->e.Id = DSIG_ID;
  475. DBG_TRC(("A(%d) E(%08x) assign SIG",
  476. e->adapter->adapter_nr, e));
  477. break;
  478. case DIVA_UM_IDI_REQ_TYPE_NET:
  479. e->e.Id = NL_ID;
  480. DBG_TRC(("A(%d) E(%08x) assign NET",
  481. e->adapter->adapter_nr, e));
  482. break;
  483. default:
  484. DBG_ERR(("A: A(%d) E(%08x) unknown type=%08x",
  485. e->adapter->adapter_nr, e,
  486. type));
  487. return (-1);
  488. }
  489. }
  490. e->e.XNum = 1;
  491. e->e.RNum = 1;
  492. e->e.callback = diva_um_idi_xdi_callback;
  493. e->e.X = &e->XData;
  494. e->e.R = &e->RData;
  495. assign = 1;
  496. }
  497. e->status |= DIVA_UM_IDI_RC_PENDING;
  498. e->e.Req = Req;
  499. e->e.ReqCh = (byte) req->ReqCh;
  500. e->e.X->PLength = (word) req->data_length;
  501. e->e.X->P = (byte *)&req[1]; /* Our buffer is safe */
  502. DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
  503. e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
  504. e->e.ReqCh, e->e.X->PLength));
  505. e->rc_count++;
  506. if (e->adapter && e->adapter->d.request) {
  507. diva_um_idi_start_wdog(e);
  508. (*(e->adapter->d.request)) (&e->e);
  509. }
  510. if (assign) {
  511. if (e->e.Rc == OUT_OF_RESOURCES) {
  512. /*
  513. XDI has no entities more, call was not forwarded to the card,
  514. no callback will be scheduled
  515. */
  516. DBG_ERR(("A: A(%d) E(%08x) XDI out of entities",
  517. e->adapter->adapter_nr, e));
  518. e->e.Id = 0;
  519. e->e.ReqCh = 0;
  520. e->e.RcCh = 0;
  521. e->e.Ind = 0;
  522. e->e.IndCh = 0;
  523. e->e.XNum = 0;
  524. e->e.RNum = 0;
  525. e->e.callback = NULL;
  526. e->e.X = NULL;
  527. e->e.R = NULL;
  528. write_return_code(e, ASSIGN_RC | OUT_OF_RESOURCES);
  529. return (-2);
  530. } else {
  531. e->status |= DIVA_UM_IDI_ASSIGN_PENDING;
  532. }
  533. }
  534. return (0);
  535. }
  536. static int process_idi_rc(divas_um_idi_entity_t *e, byte rc)
  537. {
  538. DBG_TRC(("A(%d) E(%08x) rc(%02x-%02x-%02x)",
  539. e->adapter->adapter_nr, e, e->e.Id, rc, e->e.RcCh));
  540. if (e->status & DIVA_UM_IDI_ASSIGN_PENDING) {
  541. e->status &= ~DIVA_UM_IDI_ASSIGN_PENDING;
  542. if (rc != ASSIGN_OK) {
  543. DBG_ERR(("A: A(%d) E(%08x) ASSIGN failed",
  544. e->adapter->adapter_nr, e));
  545. e->e.callback = NULL;
  546. e->e.Id = 0;
  547. e->e.Req = 0;
  548. e->e.ReqCh = 0;
  549. e->e.Rc = 0;
  550. e->e.RcCh = 0;
  551. e->e.Ind = 0;
  552. e->e.IndCh = 0;
  553. e->e.X = NULL;
  554. e->e.R = NULL;
  555. e->e.XNum = 0;
  556. e->e.RNum = 0;
  557. }
  558. }
  559. if ((e->e.Req == REMOVE) && e->e.Id && (rc == 0xff)) {
  560. DBG_ERR(("A: A(%d) E(%08x) discard OK in REMOVE",
  561. e->adapter->adapter_nr, e));
  562. return (0); /* let us do it in the driver */
  563. }
  564. if ((e->e.Req == REMOVE) && (!e->e.Id)) { /* REMOVE COMPLETE */
  565. e->e.callback = NULL;
  566. e->e.Id = 0;
  567. e->e.Req = 0;
  568. e->e.ReqCh = 0;
  569. e->e.Rc = 0;
  570. e->e.RcCh = 0;
  571. e->e.Ind = 0;
  572. e->e.IndCh = 0;
  573. e->e.X = NULL;
  574. e->e.R = NULL;
  575. e->e.XNum = 0;
  576. e->e.RNum = 0;
  577. e->rc_count = 0;
  578. }
  579. if ((e->e.Req == REMOVE) && (rc != 0xff)) { /* REMOVE FAILED */
  580. DBG_ERR(("A: A(%d) E(%08x) REMOVE FAILED",
  581. e->adapter->adapter_nr, e));
  582. }
  583. write_return_code(e, rc);
  584. return (1);
  585. }
  586. static int process_idi_ind(divas_um_idi_entity_t *e, byte ind)
  587. {
  588. int do_wakeup = 0;
  589. if (e->e.complete != 0x02) {
  590. diva_um_idi_ind_hdr_t *pind =
  591. (diva_um_idi_ind_hdr_t *)
  592. diva_data_q_get_segment4write(&e->data);
  593. if (pind) {
  594. e->e.RNum = 1;
  595. e->e.R->P = (byte *)&pind[1];
  596. e->e.R->PLength =
  597. (word) (diva_data_q_get_max_length(&e->data) -
  598. sizeof(*pind));
  599. DBG_TRC(("A(%d) E(%08x) ind_1(%02x-%02x-%02x)-[%d-%d]",
  600. e->adapter->adapter_nr, e, e->e.Id, ind,
  601. e->e.IndCh, e->e.RLength,
  602. e->e.R->PLength));
  603. } else {
  604. DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-RNR",
  605. e->adapter->adapter_nr, e, e->e.Id, ind,
  606. e->e.IndCh));
  607. e->e.RNum = 0;
  608. e->e.RNR = 1;
  609. do_wakeup = 1;
  610. }
  611. } else {
  612. diva_um_idi_ind_hdr_t *pind =
  613. (diva_um_idi_ind_hdr_t *) (e->e.R->P);
  614. DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-[%d]",
  615. e->adapter->adapter_nr, e, e->e.Id, ind,
  616. e->e.IndCh, e->e.R->PLength));
  617. pind--;
  618. pind->type = DIVA_UM_IDI_IND;
  619. pind->hdr.ind.Ind = ind;
  620. pind->hdr.ind.IndCh = e->e.IndCh;
  621. pind->data_length = e->e.R->PLength;
  622. diva_data_q_ack_segment4write(&e->data,
  623. (int) (sizeof(*pind) +
  624. e->e.R->PLength));
  625. do_wakeup = 1;
  626. }
  627. if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
  628. do_wakeup = 0;
  629. }
  630. return (do_wakeup);
  631. }
  632. /* --------------------------------------------------------------------------
  633. Write return code to the return code queue of entity
  634. -------------------------------------------------------------------------- */
  635. static int write_return_code(divas_um_idi_entity_t *e, byte rc)
  636. {
  637. diva_um_idi_ind_hdr_t *prc;
  638. if (!(prc =
  639. (diva_um_idi_ind_hdr_t *) diva_data_q_get_segment4write(&e->rc)))
  640. {
  641. DBG_ERR(("A: A(%d) E(%08x) rc(%02x) lost",
  642. e->adapter->adapter_nr, e, rc));
  643. e->status &= ~DIVA_UM_IDI_RC_PENDING;
  644. return (-1);
  645. }
  646. prc->type = DIVA_UM_IDI_IND_RC;
  647. prc->hdr.rc.Rc = rc;
  648. prc->hdr.rc.RcCh = e->e.RcCh;
  649. prc->data_length = 0;
  650. diva_data_q_ack_segment4write(&e->rc, sizeof(*prc));
  651. return (0);
  652. }
  653. /* --------------------------------------------------------------------------
  654. Return amount of entries that can be bead from this entity or
  655. -1 if adapter was removed
  656. -------------------------------------------------------------------------- */
  657. int diva_user_mode_idi_ind_ready(void *entity, void *os_handle)
  658. {
  659. divas_um_idi_entity_t *e;
  660. diva_um_idi_adapter_t *a;
  661. diva_os_spin_lock_magic_t old_irql;
  662. int ret;
  663. if (!entity)
  664. return (-1);
  665. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "ind_ready");
  666. e = (divas_um_idi_entity_t *) entity;
  667. a = e->adapter;
  668. if ((!a) || (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
  669. /*
  670. Adapter was unloaded
  671. */
  672. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
  673. return (-1); /* adapter was removed */
  674. }
  675. if (e->status & DIVA_UM_IDI_REMOVED) {
  676. /*
  677. entity was removed as result of adapter removal
  678. user should assign this entity again
  679. */
  680. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
  681. return (-1);
  682. }
  683. ret = e->rc.count + e->data.count;
  684. if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
  685. ret = 0;
  686. }
  687. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
  688. return (ret);
  689. }
  690. void *diva_um_id_get_os_context(void *entity)
  691. {
  692. return (((divas_um_idi_entity_t *) entity)->os_context);
  693. }
  694. int divas_um_idi_entity_assigned(void *entity)
  695. {
  696. divas_um_idi_entity_t *e;
  697. diva_um_idi_adapter_t *a;
  698. int ret;
  699. diva_os_spin_lock_magic_t old_irql;
  700. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "assigned?");
  701. e = (divas_um_idi_entity_t *) entity;
  702. if (!e || (!(a = e->adapter)) ||
  703. (e->status & DIVA_UM_IDI_REMOVED) ||
  704. (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
  705. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
  706. return (0);
  707. }
  708. e->status |= DIVA_UM_IDI_REMOVE_PENDING;
  709. ret = (e->e.Id || e->rc_count
  710. || (e->status & DIVA_UM_IDI_ASSIGN_PENDING));
  711. DBG_TRC(("Id:%02x, rc_count:%d, status:%08x", e->e.Id, e->rc_count,
  712. e->status))
  713. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
  714. return (ret);
  715. }
  716. int divas_um_idi_entity_start_remove(void *entity)
  717. {
  718. divas_um_idi_entity_t *e;
  719. diva_um_idi_adapter_t *a;
  720. diva_os_spin_lock_magic_t old_irql;
  721. diva_os_enter_spin_lock(&adapter_lock, &old_irql, "start_remove");
  722. e = (divas_um_idi_entity_t *) entity;
  723. if (!e || (!(a = e->adapter)) ||
  724. (e->status & DIVA_UM_IDI_REMOVED) ||
  725. (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
  726. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
  727. return (0);
  728. }
  729. if (e->rc_count) {
  730. /*
  731. Entity BUSY
  732. */
  733. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
  734. return (1);
  735. }
  736. if (!e->e.Id) {
  737. /*
  738. Remove request was already pending, and arrived now
  739. */
  740. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
  741. return (0); /* REMOVE was pending */
  742. }
  743. /*
  744. Now send remove request
  745. */
  746. e->e.Req = REMOVE;
  747. e->e.ReqCh = 0;
  748. e->rc_count++;
  749. DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
  750. e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
  751. e->e.ReqCh, e->e.X->PLength));
  752. if (a->d.request)
  753. (*(a->d.request)) (&e->e);
  754. diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
  755. return (0);
  756. }