1/*
2 * Copyright 2004-2013, Haiku, Inc. All RightsReserved.
3 * Copyright 2002-2003, Thomas Kurschel. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8//!	Main file.
9
10
11#include "scsi_periph_int.h"
12
13#include <module.h>
14
15#include <string.h>
16
17
18device_manager_info* gDeviceManager;
19
20
21status_t
22periph_simple_exec(scsi_periph_device_info* device, void* cdb, uchar cdbLength,
23	void* data, size_t dataLength, int ccb_flags)
24{
25	SHOW_FLOW0( 0, "" );
26
27	scsi_ccb* ccb = device->scsi->alloc_ccb(device->scsi_device);
28	if (ccb == NULL)
29		return B_NO_MEMORY;
30
31	ccb->flags = ccb_flags;
32
33	memcpy(ccb->cdb, cdb, cdbLength);
34	ccb->cdb_length = cdbLength;
35
36	ccb->sort = -1;
37	ccb->timeout = device->std_timeout;
38
39	ccb->data = (uint8*)data;
40	ccb->sg_list = NULL;
41	ccb->data_length = dataLength;
42
43	status_t status = periph_safe_exec(device, ccb);
44
45	device->scsi->free_ccb(ccb);
46
47	return status;
48}
49
50
51status_t
52periph_safe_exec(scsi_periph_device_info *device, scsi_ccb *request)
53{
54	err_res res;
55	int retries = 0;
56
57	do {
58		device->scsi->sync_io(request);
59
60		// ask generic peripheral layer what to do now
61		res = periph_check_error(device, request);
62		if (res.action == err_act_start) {
63			// backup request, as we need it temporarily for sending "start"
64			// (we cannot allocate a new cdb as there may be no more cdb and
65			//  waiting for one to become empty may lead to deadlock if everyone
66			//  does that)
67			uint32 backup_flags;
68			uint8 backup_cdb[SCSI_MAX_CDB_SIZE];
69			uchar backup_cdb_len;
70			int64 backup_sort;
71			bigtime_t backup_timeout;
72			uchar *backup_data;
73			const physical_entry *backup_sg_list;
74			uint16 backup_sg_count;
75			uint32 backup_data_len;
76
77			backup_flags = request->flags;
78			memcpy(backup_cdb, request->cdb, SCSI_MAX_CDB_SIZE);
79			backup_cdb_len = request->cdb_length;
80			backup_sort = request->sort;
81			backup_timeout = request->timeout;
82			backup_data = request->data;
83			backup_sg_list = request->sg_list;
84			backup_sg_count = request->sg_count;
85			backup_data_len = request->data_length;
86
87			SHOW_INFO0( 2, "Sending start to init LUN" );
88
89			res = periph_send_start_stop(device, request, 1, device->removable);
90
91			request->flags = backup_flags;
92			memcpy(request->cdb, backup_cdb, SCSI_MAX_CDB_SIZE);
93			request->cdb_length = backup_cdb_len;
94			request->sort = backup_sort;
95			request->timeout = backup_timeout;
96			request->data = backup_data;
97			request->sg_list = backup_sg_list;
98			request->sg_count = backup_sg_count;
99			request->data_length = backup_data_len;
100
101			if (res.action == err_act_ok)
102				res.action = err_act_retry;
103		}
104	} while ((res.action == err_act_retry && retries++ < 3)
105		|| (res.action == err_act_many_retries && retries++ < 30));
106
107	return res.error_code;
108}
109
110
111module_dependency module_dependencies[] = {
112	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
113	{}
114};
115
116
117static scsi_periph_interface sSCSIPeripheralModule = {
118	{
119		SCSI_PERIPH_MODULE_NAME,
120		0,
121		NULL
122	},
123
124	periph_register_device,
125	periph_unregister_device,
126
127	periph_safe_exec,
128	periph_simple_exec,
129
130	periph_handle_open,
131	periph_handle_close,
132	periph_handle_free,
133
134	periph_read_write,
135	periph_io,
136	periph_ioctl,
137	periph_check_capacity,
138	periph_synchronize_cache,
139	periph_trim_device,
140
141	periph_media_changed_public,
142	periph_check_error,
143	periph_send_start_stop,
144	periph_get_media_status,
145
146	periph_compose_device_name
147};
148
149scsi_periph_interface *modules[] = {
150	&sSCSIPeripheralModule,
151	NULL
152};
153