|
|
1.1 root 1: /*
2: * Hatari - nf_scsidrv.c
3: *
1.1.1.2 ! root 4: * Copyright (C) 2015-2016, 2018 by Uwe Seimet
1.1 root 5: *
6: * This file is distributed under the GNU General Public License, version 2
7: * or at your option any later version. Read the file gpl.txt for details.
8: *
9: * nf_scsidrv.c - Implementation of the host system part of a SCSI Driver
10: * (Linux only), based on the Linux SG driver version 3. The corresponding
11: * TOS binary and its source code can be downloaded from
12: * http://hddriver.seimet.de/en/downloads.html, where you can also find
13: * information on the open SCSI Driver standard.
14: */
15: const char NfScsiDrv_fileid[] = "Hatari nf_scsidrv.c : " __DATE__ " " __TIME__;
16:
17: #if defined(__linux__)
18:
19: #include "config.h"
20: #include <stdlib.h>
21: #include <unistd.h>
22: #include <fcntl.h>
23: #if HAVE_UDEV
24: #include <libudev.h>
25: #endif
26: #include <sys/ioctl.h>
27: #include <scsi/sg.h>
28: #include "stMemory.h"
29: #include "log.h"
30: #include "gemdos_defines.h"
1.1.1.2 ! root 31: #include "m68000.h"
1.1 root 32: #include "nf_scsidrv.h"
33:
34: // The driver interface version, 1.02
35: #define INTERFACE_VERSION 0x0102
36: // Maximum is 20 characters
37: #define BUS_NAME "Linux Generic SCSI"
38: // The SG driver supports cAllCmds
39: #define BUS_FEATURES 0x02
40: // The transfer length may depend on the device, 65536 should always be safe
41: #define BUS_TRANSFER_LEN 65536
42: // The maximum number of SCSI Driver handles, must be the same as in the stub
43: #define SCSI_MAX_HANDLES 32
44:
45:
46: typedef struct
47: {
48: int fd;
49: int id_lo;
50: int error;
51: } HANDLE_META_DATA;
52:
53: static HANDLE_META_DATA handle_meta_data[SCSI_MAX_HANDLES];
54:
55: #if HAVE_UDEV
56: static struct udev *udev;
57: static struct udev_monitor *mon;
58: static int udev_mon_fd;
59: static struct timeval tv;
60: #endif
61:
62: static Uint32 read_stack_long(Uint32 *stack)
63: {
64: Uint32 value = STMemory_ReadLong(*stack);
65:
66: *stack += SIZE_LONG;
67:
68: return value;
69: }
70:
71: static void *read_stack_pointer(Uint32 *stack)
72: {
73: Uint32 ptr = read_stack_long(stack);
74: return ptr ? STMemory_STAddrToPointer(ptr) : 0;
75: }
76:
77: static void write_long(Uint32 addr, Uint32 value)
78: {
79: STMemory_WriteLong(addr, value);
80: }
81:
82: static void write_word(Uint32 addr, Uint16 value)
83: {
84: STMemory_WriteWord(addr, value);
85: }
86:
87: // Sets the error status
88: static void set_error(Uint32 handle, int errbit)
89: {
90: Uint32 i;
91: for (i = 0; i < SCSI_MAX_HANDLES; i++)
92: {
93: if (handle != i && handle_meta_data[i].fd &&
94: handle_meta_data[i].id_lo == handle_meta_data[handle].id_lo)
95: {
96: handle_meta_data[i].error |= errbit;
97: }
98: }
99: }
100:
101: // udev-based check for media change. When udev is active media change messages
102: // are handled globally by udev, i.e. that media changes cannot directly be
103: // detected by the SCSI Driver. The SCSI Driver has to query udev instead.
104: static bool check_mchg_udev(void)
105: {
106: bool changed = false;
107:
108: #if HAVE_UDEV
109: fd_set udevFds;
110: int ret;
111:
112: FD_ZERO(&udevFds);
113: FD_SET(udev_mon_fd, &udevFds);
114:
115: ret = select(udev_mon_fd + 1, &udevFds, 0, 0, &tv);
116: if (ret > 0 && FD_ISSET(udev_mon_fd, &udevFds))
117: {
118: struct udev_device *dev = udev_monitor_receive_device(mon);
119: while (dev)
120: {
121: if (!changed)
122: {
123: const char *dev_type = udev_device_get_devtype(dev);
124: const char *action = udev_device_get_action(dev);
125: if (!strcmp("disk", dev_type) && !strcmp("change", action))
126: {
127: LOG_TRACE(TRACE_SCSIDRV, ": %s has been changed",
128: udev_device_get_devnode(dev));
129:
130: // TODO Determine sg device name from block device name and
131: // only report media change for the actually affected device
132:
133: changed = true;
134: }
135: }
136:
137: // Process all pending events
138: dev = udev_monitor_receive_device(mon);
139: }
140: }
141: #endif
142:
143: return changed;
144: }
145:
146: // Checks whether a device exists by checking for the device file name
147: static int check_device_file(Uint32 id)
148: {
149: char device_file[16];
150: sprintf(device_file, "/dev/sg%d", id);
151:
152: if (!access(device_file, R_OK | W_OK))
153: {
154: LOG_TRACE(TRACE_SCSIDRV, ", device file %s is accessible",
155: device_file);
156:
157: return 0;
158: }
159: else
160: {
161: LOG_TRACE(TRACE_SCSIDRV, ", device file %s is inaccessible",
162: device_file);
163:
164: return -1;
165: }
166: }
167:
168: static int scsidrv_interface_version(Uint32 stack)
169: {
1.1.1.2 ! root 170: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_interface_version: version=$%04x", INTERFACE_VERSION);
! 171:
1.1 root 172: return INTERFACE_VERSION;
173: }
174:
175: static int scsidrv_interface_features(Uint32 stack)
176: {
1.1.1.2 ! root 177: Uint32 st_bus_name = STMemory_ReadLong(stack);
1.1 root 178: char *busName = read_stack_pointer(&stack);
179: Uint32 features = read_stack_long(&stack);
180: Uint32 transferLen = read_stack_long(&stack);
181:
1.1.1.2 ! root 182: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_interface_features: busName=%s, features=$%04x, transferLen=%d", BUS_NAME, BUS_FEATURES, BUS_TRANSFER_LEN);
! 183:
! 184: if ( !STMemory_CheckAreaType ( st_bus_name, 20, ABFLAG_RAM ) )
! 185: {
! 186: Log_Printf(LOG_WARN, "scsidrv_interface_features: Invalid RAM range 0x%x+%i\n", st_bus_name, 20);
! 187: return -1;
! 188: }
! 189:
1.1 root 190: strncpy(busName, BUS_NAME, 20);
1.1.1.2 ! root 191: M68000_Flush_Data_Cache(st_bus_name, 20);
1.1 root 192: write_word(features, BUS_FEATURES);
193: write_long(transferLen, BUS_TRANSFER_LEN);
194:
195: return 0;
196: }
197:
198: // SCSI Driver: InquireBus()
199: static int scsidrv_inquire_bus(Uint32 stack)
200: {
201: Uint32 id = read_stack_long(&stack);
202: char device_file[16];
203:
204: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_inquire_bus: id=%d", id);
205:
206: sprintf(device_file, "/dev/sg%d", id);
207:
208: while (!access(device_file, F_OK))
209: {
210: if (!check_device_file(id))
211: {
212: return id;
213: }
214:
215: sprintf(device_file, "/dev/sg%d", ++id);
216: }
217:
218: return -1;
219: }
220:
221: // SCSI Driver: Open()
222: static int scsidrv_open(Uint32 stack)
223: {
224: char device_file[16];
225: Uint32 handle;
226: Uint32 id;
227: int fd;
228:
229: #if HAVE_UDEV
230: if (!udev)
231: {
232: udev = udev_new();
233: if (!udev)
234: {
235: return -1;
236: }
237:
238: mon = udev_monitor_new_from_netlink(udev, "udev");
239: udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL);
240: udev_monitor_enable_receiving(mon);
241: udev_mon_fd = udev_monitor_get_fd(mon);
242:
243: tv.tv_sec = 0;
244: tv.tv_usec = 0;
245: }
246: #endif
247:
248: handle = read_stack_long(&stack);
249: id = read_stack_long(&stack);
250:
251: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_open: handle=%d, id=%d", handle, id);
252:
253: if (handle >= SCSI_MAX_HANDLES || handle_meta_data[handle].fd ||
254: check_device_file(id))
255: {
256: return GEMDOS_ENHNDL;
257: }
258:
259: sprintf(device_file, "/dev/sg%d", id);
260:
261: fd = open(device_file, O_RDWR | O_NONBLOCK);
262: if (fd < 0)
263: {
264: return fd;
265: }
266:
267: handle_meta_data[handle].fd = fd;
268: handle_meta_data[handle].id_lo = id;
269: handle_meta_data[handle].error = 0;
270:
271: return 0;
272: }
273:
274: // SCSI Driver: Close()
275: static int scsidrv_close(Uint32 stack)
276: {
277: Uint32 handle = read_stack_long(&stack);
278:
279: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_close: handle=%d", handle);
280:
281: if (handle >= SCSI_MAX_HANDLES || !handle_meta_data[handle].fd)
282: {
283: return GEMDOS_ENHNDL;
284: }
285:
286: close(handle_meta_data[handle].fd);
287:
288: handle_meta_data[handle].fd = 0;
289:
290: return 0;
291: }
292:
293: // SCSI Driver: In() and Out()
294: static int scsidrv_inout(Uint32 stack)
295: {
296: Uint32 handle = read_stack_long(&stack);
297: Uint32 dir = read_stack_long(&stack);
298: unsigned char *cmd = read_stack_pointer(&stack);
299: Uint32 cmd_len = read_stack_long(&stack);
1.1.1.2 ! root 300: Uint32 st_buffer = STMemory_ReadLong(stack);
1.1 root 301: unsigned char *buffer = read_stack_pointer(&stack);
302: Uint32 transfer_len = read_stack_long(&stack);
1.1.1.2 ! root 303: Uint32 st_sense_buffer = STMemory_ReadLong(stack);
1.1 root 304: unsigned char *sense_buffer = read_stack_pointer(&stack);
1.1.1.2 ! root 305: Uint32 timeout = read_stack_long(&stack);
1.1 root 306: int status;
307:
308: if (LOG_TRACE_LEVEL(TRACE_SCSIDRV))
309: {
310: LOG_TRACE_PRINT(
311: "scsidrv_inout: handle=%d, dir=%d, cmd_len=%d, buffer=%p,\n"
312: " transfer_len=%d, sense_buffer=%p, timeout=%d,\n"
313: " cmd=",
314: handle, dir, cmd_len, buffer, transfer_len, sense_buffer,
315: timeout);
316:
317: Uint32 i;
318: for (i = 0; i < cmd_len; i++)
319: {
320: char str[8];
321: sprintf(str, i ? ":$%02X" : "$%02X", cmd[i]);
322: LOG_TRACE_PRINT("%s", str);
323: }
324: }
325:
1.1.1.2 ! root 326: // Writing is allowed with a RAM or ROM address,
! 327: // reading requires a RAM address
! 328: if ( !STMemory_CheckAreaType ( st_buffer, transfer_len, dir ? ABFLAG_RAM | ABFLAG_ROM : ABFLAG_RAM ) )
! 329: {
! 330: Log_Printf(LOG_WARN, "scsidrv_inout: Invalid RAM range 0x%x+%i\n", st_buffer, transfer_len);
! 331: return -1;
! 332: }
! 333:
1.1 root 334: if (handle >= SCSI_MAX_HANDLES || !handle_meta_data[handle].fd)
335: {
336: return GEMDOS_ENHNDL;
337: }
338:
1.1.1.2 ! root 339: if (sense_buffer)
! 340: {
! 341: memset(sense_buffer, 0, 18);
! 342: }
! 343:
1.1 root 344: // No explicit LUN support, the SG driver maps LUNs to device files
345: if (cmd[1] & 0xe0)
346: {
347: if (sense_buffer)
348: {
349: // Sense Key and ASC
350: sense_buffer[2] = 0x05;
351: sense_buffer[12] = 0x25;
1.1.1.2 ! root 352: M68000_Flush_Data_Cache(st_sense_buffer, 18);
1.1 root 353:
354: LOG_TRACE(TRACE_SCSIDRV,
355: "\n Sense Key=$%02X, ASC=$%02X, ASCQ=$00",
356: sense_buffer[2], sense_buffer[12]);
357: }
358:
359: return 2;
360: }
361:
362: if (check_mchg_udev())
363: {
364: // cErrMediach for all open handles
365: Uint32 i;
366: for (i = 0; i < SCSI_MAX_HANDLES; i++)
367: {
368: if (handle_meta_data[i].fd)
369: {
370: handle_meta_data[i].error |= 1;
371: }
372: }
373:
374: if (sense_buffer)
375: {
376: // Sense Key and ASC
377: sense_buffer[2] = 0x06;
378: sense_buffer[12] = 0x28;
379: }
380:
381: status = 2;
382: }
383: else
384: {
385: struct sg_io_hdr io_hdr;
386: memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
387:
388: io_hdr.interface_id = 'S';
389:
390: io_hdr.dxfer_direction = dir ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
391: if (!transfer_len)
392: {
393: io_hdr.dxfer_direction = SG_DXFER_NONE;
394: }
395:
396: io_hdr.dxferp = buffer;
397: io_hdr.dxfer_len = transfer_len;
398:
399: io_hdr.sbp = sense_buffer;
400: io_hdr.mx_sb_len = 18;
401:
402: io_hdr.cmdp = cmd;
403: io_hdr.cmd_len = cmd_len;
404:
405: io_hdr.timeout = timeout;
406:
407: status = ioctl(handle_meta_data[handle].fd,
408: SG_IO, &io_hdr) < 0 ? -1 : io_hdr.status;
409: }
410:
411: if (status > 0 && sense_buffer)
412: {
413: LOG_TRACE(TRACE_SCSIDRV,
414: "\n Sense Key=$%02X, ASC=$%02X, ASCQ=$%02X",
415: sense_buffer[2], sense_buffer[12], sense_buffer[13]);
416:
417: if (status == 2)
418: {
419: // Automatic media change and reset handling for
420: // SCSI Driver version 1.0.1
421: if ((sense_buffer[2] & 0x0f) && !sense_buffer[13])
422: {
423: if (sense_buffer[12] == 0x28)
424: {
425: // cErrMediach
426: set_error(handle, 1);
427: }
428: else if (sense_buffer[12] == 0x29)
429: {
430: // cErrReset
431: set_error(handle, 2);
432: }
433: }
434: }
435: }
436:
1.1.1.2 ! root 437: M68000_Flush_Data_Cache(st_sense_buffer, 18);
! 438: if (!dir)
! 439: {
! 440: M68000_Flush_All_Caches(st_buffer, transfer_len);
! 441: }
! 442:
1.1 root 443: return status;
444: }
445:
446: // SCSI Driver: Error()
447: static int scsidrv_error(Uint32 stack)
448: {
449: Uint32 handle = read_stack_long(&stack);
450: Uint32 rwflag = read_stack_long(&stack);
451: Uint32 errnum = read_stack_long(&stack);
452: int errbit;
453:
454: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_error: handle=%d, rwflag=%d, errno=%d",
455: handle, rwflag, errnum);
456:
457: if (handle >= SCSI_MAX_HANDLES || !handle_meta_data[handle].fd)
458: {
459: return GEMDOS_ENHNDL;
460: }
461:
462: errbit = 1 << errnum;
463:
464: if (rwflag)
465: {
466: set_error(handle, errbit);
467:
468: return 0;
469: }
470: else
471: {
472: int status = handle_meta_data[handle].error & errbit;
473: handle_meta_data[handle].error &= ~errbit;
474:
475: return status;
476: }
477: }
478:
479: // SCSI Driver: CheckDev()
480: static int scsidrv_check_dev(Uint32 stack)
481: {
482: Uint32 id = read_stack_long(&stack);
483:
484: LOG_TRACE(TRACE_SCSIDRV, "scsidrv_check_dev: id=%d", id);
485:
486: return check_device_file(id);
487: }
488:
489: static const struct
490: {
491: int (*cb)(Uint32 stack);
492: } operations[] =
493: {
494: { scsidrv_interface_version },
495: { scsidrv_interface_features },
496: { scsidrv_inquire_bus },
497: { scsidrv_open },
498: { scsidrv_close },
499: { scsidrv_inout },
500: { scsidrv_error },
501: { scsidrv_check_dev }
502: };
503:
504: bool nf_scsidrv(Uint32 stack, Uint32 subid, Uint32 *retval)
505: {
506: if (subid >= ARRAY_SIZE(operations))
507: {
508: *retval = -1;
509:
510: LOG_TRACE(TRACE_SCSIDRV,
511: "ERROR: Invalid SCSI Driver operation %d requested\n", subid);
512: }
513: else
514: {
515: *retval = operations[subid].cb(stack);
516:
517: LOG_TRACE(TRACE_SCSIDRV, " -> %d\n", *retval);
518: }
519:
520: return true;
521: }
522:
1.1.1.2 ! root 523: void nf_scsidrv_reset(void)
1.1 root 524: {
525: int i;
526: for (i = 0; i < SCSI_MAX_HANDLES; i++)
527: {
528: if (handle_meta_data[i].fd)
529: {
530: close(handle_meta_data[i].fd);
531:
532: handle_meta_data[i].fd = 0;
533: }
534: }
535: }
536:
537: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.