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
18 device_manager_info* gDeviceManager;
19
20
21 status_t
periph_simple_exec(scsi_periph_device_info * device,void * cdb,uchar cdbLength,void * data,size_t dataLength,int ccb_flags)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
periph_safe_exec(scsi_periph_device_info * device,scsi_ccb * request)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_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
149 scsi_periph_interface *modules[] = {
150 &sSCSIPeripheralModule,
151 NULL
152 };
153