26 |
|
#include <unistd.h> |
27 |
|
#include <errno.h> |
28 |
|
|
29 |
+ |
#define DRIVER_SENSE 0x08 |
30 |
+ |
|
31 |
|
#include "main.h" |
32 |
|
#include "prefs.h" |
33 |
|
#include "user_strings.h" |
65 |
|
sprintf(prefs_name, "scsi%d", id); |
66 |
|
const char *str = PrefsFindString(prefs_name); |
67 |
|
if (str) { |
68 |
< |
int fd = fds[id] = open(str, O_RDWR); |
68 |
> |
int fd = fds[id] = open(str, O_RDWR | O_EXCL); |
69 |
|
if (fd > 0) { |
70 |
|
// Is it really a Generic SCSI device? |
71 |
|
int timeout = ioctl(fd, SG_GET_TIMEOUT); |
124 |
|
|
125 |
|
static bool try_buffer(uint32 size) |
126 |
|
{ |
127 |
< |
size += sizeof(struct sg_header) + 12; |
127 |
> |
size += sizeof(sg_header) + 12; |
128 |
|
if (size <= buffer_size) |
129 |
|
return true; |
130 |
|
|
168 |
|
if (new_fd < 0) |
169 |
|
return false; |
170 |
|
if (new_fd != fd) { |
171 |
< |
// Clear autosense data |
172 |
< |
struct sg_header *h = (struct sg_header *)buffer; |
173 |
< |
h->sense_buffer[2] = 0; |
171 |
> |
// New target, clear autosense data |
172 |
> |
sg_header *h = (sg_header *)buffer; |
173 |
> |
h->driver_status &= ~DRIVER_SENSE; |
174 |
|
} |
175 |
|
fd = new_fd; |
176 |
|
return true; |
197 |
|
// Process S/G table when writing |
198 |
|
if (!reading) { |
199 |
|
D(bug(" writing to buffer\n")); |
200 |
< |
uint8 *buffer_ptr = buffer + sizeof(struct sg_header) + the_cmd_len; |
200 |
> |
uint8 *buffer_ptr = buffer + sizeof(sg_header) + the_cmd_len; |
201 |
|
for (int i=0; i<sg_size; i++) { |
202 |
|
uint32 len = sg_len[i]; |
203 |
|
D(bug(" %d bytes from %08lx\n", len, sg_ptr[i])); |
207 |
|
} |
208 |
|
|
209 |
|
// Request Sense and autosense data valid? |
210 |
< |
struct sg_header *h = (struct sg_header *)buffer; |
210 |
> |
sg_header *h = (sg_header *)buffer; |
211 |
|
int res; |
212 |
< |
if (the_cmd[0] == 0x03 && (h->sense_buffer[2] & 0x0f)) { |
212 |
> |
if (reading && the_cmd[0] == 0x03 && (h->target_status & DRIVER_SENSE)) { |
213 |
|
|
214 |
|
// Yes, fake command |
215 |
|
D(bug(" autosense\n")); |
216 |
< |
memcpy(buffer + sizeof(struct sg_header), h->sense_buffer, 16); |
216 |
> |
memcpy(buffer + sizeof(sg_header), h->sense_buffer, 16); |
217 |
> |
h->target_status &= ~DRIVER_SENSE; |
218 |
|
res = 0; |
219 |
|
*stat = 0; |
220 |
|
|
221 |
|
} else { |
222 |
|
|
223 |
|
// No, send regular command |
224 |
< |
int to = timeout * HZ / 60; |
225 |
< |
ioctl(fd, SG_SET_TIMEOUT, &to); |
224 |
> |
if (timeout) { |
225 |
> |
int to = timeout * HZ / 60; |
226 |
> |
ioctl(fd, SG_SET_TIMEOUT, &to); |
227 |
> |
} |
228 |
> |
ioctl(fd, SG_NEXT_CMD_LEN, &the_cmd_len); |
229 |
> |
|
230 |
|
D(bug(" sending command, length %d\n", data_length)); |
231 |
+ |
|
232 |
|
int request_size, reply_size; |
233 |
|
if (reading) { |
234 |
< |
h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len; |
235 |
< |
h->reply_len = reply_size = sizeof(struct sg_header) + data_length; |
234 |
> |
h->pack_len = request_size = sizeof(sg_header) + the_cmd_len; |
235 |
> |
h->reply_len = reply_size = sizeof(sg_header) + data_length; |
236 |
|
} else { |
237 |
< |
h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len + data_length; |
238 |
< |
h->reply_len = reply_size = sizeof(struct sg_header); |
237 |
> |
h->pack_len = request_size = sizeof(sg_header) + the_cmd_len + data_length; |
238 |
> |
h->reply_len = reply_size = sizeof(sg_header); |
239 |
|
} |
240 |
|
h->pack_id = pack_id++; |
241 |
|
h->result = 0; |
242 |
|
h->twelve_byte = (the_cmd_len == 12); |
243 |
< |
h->sense_buffer[2] = 0; |
244 |
< |
memcpy(buffer + sizeof(struct sg_header), the_cmd, the_cmd_len); |
243 |
> |
h->target_status = 0; |
244 |
> |
h->host_status = 0; |
245 |
> |
h->driver_status = 0; |
246 |
> |
h->other_flags = 0; |
247 |
> |
memcpy(buffer + sizeof(sg_header), the_cmd, the_cmd_len); |
248 |
> |
|
249 |
|
res = write(fd, buffer, request_size); |
250 |
|
D(bug(" request sent, actual %d, result %d\n", res, h->result)); |
251 |
|
if (res >= 0) { |
252 |
|
res = read(fd, buffer, reply_size); |
253 |
< |
D(bug(" reply read, actual %d, result %d\n", res, h->result)); |
253 |
> |
D(bug(" reply read, actual %d, result %d, status %02x\n", res, h->result, h->target_status << 1)); |
254 |
|
} |
255 |
< |
if (h->sense_buffer[2] & 0x0f) |
256 |
< |
*stat = 2; // Check condition |
245 |
< |
else |
246 |
< |
*stat = 0; // No error |
255 |
> |
|
256 |
> |
*stat = h->target_status << 1; |
257 |
|
} |
258 |
|
|
259 |
|
// Process S/G table when reading |
260 |
|
if (reading && h->result == 0) { |
261 |
|
D(bug(" reading from buffer\n")); |
262 |
< |
uint8 *buffer_ptr = buffer + sizeof(struct sg_header); |
262 |
> |
uint8 *buffer_ptr = buffer + sizeof(sg_header); |
263 |
|
for (int i=0; i<sg_size; i++) { |
264 |
|
uint32 len = sg_len[i]; |
265 |
|
D(bug(" %d bytes to %08lx\n", len, sg_ptr[i])); |