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