xref: /haiku/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright 2004-2008, 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 
18 device_manager_info* gDeviceManager;
19 
20 
21 status_t
22 periph_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 
51 status_t
52 periph_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 
111 module_dependency module_dependencies[] = {
112 	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
113 	{}
114 };
115 
116 
117 static 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_io,
135 	periph_ioctl,
136 	periph_check_capacity,
137 
138 	periph_media_changed_public,
139 	periph_check_error,
140 	periph_send_start_stop,
141 	periph_get_media_status,
142 	periph_synchronize_cache,
143 
144 	periph_compose_device_name
145 };
146 
147 scsi_periph_interface *modules[] = {
148 	&sSCSIPeripheralModule,
149 	NULL
150 };
151