1/*
2** Copyright 2002/03, Thomas Kurschel. All rights reserved.
3** Distributed under the terms of the MIT License.
4*/
5
6/*
7	Part of Open SCSI bus manager
8
9	DPC handling (deferred procedure calls).
10
11	DPC are executed by the service thread of the bus
12	(see busses.c).
13*/
14
15#include "scsi_internal.h"
16
17#include <string.h>
18#include <stdlib.h>
19
20
21status_t
22scsi_alloc_dpc(scsi_dpc_info **dpc)
23{
24	SHOW_FLOW0(3, "");
25
26	*dpc = (scsi_dpc_info *)malloc(sizeof(scsi_dpc_info));
27	if (*dpc == NULL)
28		return B_NO_MEMORY;
29
30	memset(*dpc, 0, sizeof(scsi_dpc_info));
31	return B_OK;
32}
33
34
35status_t
36scsi_free_dpc(scsi_dpc_info *dpc)
37{
38	SHOW_FLOW0(3, "");
39
40	free(dpc);
41	return B_OK;
42}
43
44
45status_t
46scsi_schedule_dpc(scsi_bus_info *bus, scsi_dpc_info *dpc, /*int flags,*/
47	void (*func)(void *arg), void *arg)
48{
49	SHOW_FLOW(3, "bus=%p, dpc=%p", bus, dpc);
50	acquire_spinlock_irq(&bus->dpc_lock);
51
52	dpc->func = func;
53	dpc->arg = arg;
54
55	if (!dpc->registered) {
56		dpc->registered = true;
57		dpc->next = bus->dpc_list;
58		bus->dpc_list = dpc;
59	} else
60		SHOW_FLOW0(3, "already registered - ignored");
61
62	release_spinlock_irq(&bus->dpc_lock);
63
64	// this is called in IRQ context, so scheduler is not allowed
65	release_sem_etc(bus->start_service, 1, B_DO_NOT_RESCHEDULE);
66	return B_OK;
67}
68
69
70/** execute pending DPCs */
71
72bool
73scsi_check_exec_dpc(scsi_bus_info *bus)
74{
75	SHOW_FLOW(3, "bus=%p, dpc_list=%p", bus, bus->dpc_list);
76	acquire_spinlock_irq(&bus->dpc_lock);
77
78	if (bus->dpc_list) {
79		scsi_dpc_info *dpc;
80		void (*dpc_func)(void *);
81		void *dpc_arg;
82
83		dpc = bus->dpc_list;
84		bus->dpc_list = dpc->next;
85
86		dpc_func = dpc->func;
87		dpc_arg = dpc->arg;
88		dpc->registered = false;
89
90		release_spinlock_irq(&bus->dpc_lock);
91
92		dpc_func(dpc_arg);
93		return true;
94	}
95
96	release_spinlock_irq(&bus->dpc_lock);
97	return false;
98}
99
100