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	CCB manager
10
11	As allocation of ccb can be on the paging path we must use a
12	locked pool.
13*/
14
15#include "scsi_internal.h"
16
17
18
19// ccb are relatively large, so don't make it too small to not waste memory
20#define CCB_CHUNK_SIZE 16*1024
21
22// maximum number of CCBs - probably, we want to make that editable
23// it must be at least 1 for normal use and 1 for stand-by autosense request
24#define CCB_NUM_MAX 128
25
26
27scsi_ccb *
28scsi_alloc_ccb(scsi_device_info *device)
29{
30	scsi_ccb *ccb;
31
32	SHOW_FLOW0( 3, "" );
33
34	ccb = (scsi_ccb *)locked_pool->alloc(device->bus->ccb_pool);
35	ccb->state = SCSI_STATE_FINISHED;
36	ccb->device = device;
37	ccb->target_id = device->target_id;
38	ccb->target_lun = device->target_lun;
39
40	// reset some very important fields
41	// TODO: should we better omit that to find bugs easier?
42	ccb->sg_list = NULL;
43	ccb->io_operation = NULL;
44	ccb->sort = -1;
45
46	SHOW_FLOW(3, "path=%d", ccb->path_id);
47
48	return ccb;
49}
50
51
52void
53scsi_free_ccb(scsi_ccb *ccb)
54{
55	SHOW_FLOW0( 3, "" );
56
57	if (ccb->state != SCSI_STATE_FINISHED)
58		panic("Tried to free ccb that's still in use (state %d)\n", ccb->state);
59
60	ccb->state = SCSI_STATE_FREE;
61
62	locked_pool->free(ccb->bus->ccb_pool, ccb);
63}
64
65
66static status_t
67ccb_low_alloc_hook(void *block, void *arg)
68{
69	scsi_ccb *ccb = (scsi_ccb *)block;
70	scsi_bus_info *bus = (scsi_bus_info *)arg;
71	status_t res;
72
73	ccb->bus = bus;
74	ccb->path_id = bus->path_id;
75	ccb->state = SCSI_STATE_FREE;
76
77	if ((res = ccb->completion_sem = create_sem(0, "ccb_sem")) < 0)
78		return res;
79
80	return B_OK;
81}
82
83
84static void
85ccb_low_free_hook(void *block, void *arg)
86{
87	scsi_ccb *ccb = (scsi_ccb *)block;
88
89	delete_sem(ccb->completion_sem);
90}
91
92
93status_t
94scsi_init_ccb_alloc(scsi_bus_info *bus)
95{
96	// initially, we want no CCB allocated as the path_id of
97	// the bus is not ready yet so the CCB cannot be initialized
98	// correctly
99	bus->ccb_pool = locked_pool->create(sizeof(scsi_ccb), sizeof(uint32) - 1, 0,
100		CCB_CHUNK_SIZE, CCB_NUM_MAX, 0, "scsi_ccb_pool", B_CONTIGUOUS,
101		ccb_low_alloc_hook, ccb_low_free_hook, bus);
102
103	if (bus->ccb_pool == NULL)
104		return B_NO_MEMORY;
105
106	return B_OK;
107}
108
109
110void
111scsi_uninit_ccb_alloc(scsi_bus_info *bus)
112{
113	locked_pool->destroy(bus->ccb_pool);
114}
115
116