ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Linux/scsi_linux.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (25 years, 1 month ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * scsi_linux.cpp - SCSI Manager, Linux specific stuff
3     *
4     * Basilisk II (C) 1997-1999 Christian Bauer
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <sys/ioctl.h>
24     #include <linux/param.h>
25     #include <linux/../scsi/sg.h> // workaround for broken RedHat 6.0 /usr/include/scsi
26     #include <unistd.h>
27     #include <errno.h>
28    
29     #include "main.h"
30     #include "prefs.h"
31     #include "user_strings.h"
32     #include "scsi.h"
33    
34     #define DEBUG 0
35     #include "debug.h"
36    
37    
38     // Global variables
39     static int fds[8]; // fd's for 8 units
40     static int fd; // Active fd (selected target)
41    
42     static uint32 buffer_size; // Size of data buffer
43     static uint8 *buffer = NULL; // Pointer to data buffer
44    
45     static uint8 the_cmd[12]; // Active SCSI command
46     static int the_cmd_len;
47    
48    
49     /*
50     * Initialization
51     */
52    
53     void SCSIInit(void)
54     {
55     int id;
56    
57     // Allocate buffer
58     buffer = (uint8 *)malloc(buffer_size = 0x10000);
59    
60     // Open generic SCSI driver for all 8 units
61     for (id=0; id<8; id++) {
62     char prefs_name[16];
63     sprintf(prefs_name, "scsi%d", id);
64     const char *str = PrefsFindString(prefs_name);
65     if (str) {
66     int fd = fds[id] = open(str, O_RDWR);
67     if (fd > 0) {
68     // Is it really a Generic SCSI device?
69     int timeout = ioctl(fd, SG_GET_TIMEOUT);
70     if (timeout < 0) {
71     // Error with SG_GET_TIMEOUT, doesn't seem to be a Generic SCSI device
72     char msg[256];
73     sprintf(msg, GetString(STR_SCSI_DEVICE_NOT_SCSI_WARN), str);
74     WarningAlert(msg);
75     close(fd);
76     fds[id] = -1;
77     } else {
78     // Flush unwanted garbage from previous use of device
79     uint8 reply[256];
80     int old_fl = fcntl(fd, F_GETFL);
81     fcntl(fd, F_SETFL, old_fl | O_NONBLOCK);
82     while (read(fd, reply, sizeof(reply)) != -1 || errno != EAGAIN) ;
83     fcntl(fd, F_SETFL, old_fl);
84     }
85     } else {
86     char msg[256];
87     sprintf(msg, GetString(STR_SCSI_DEVICE_OPEN_WARN), str, strerror(errno));
88     WarningAlert(msg);
89     }
90     }
91     }
92    
93     // Reset SCSI bus
94     SCSIReset();
95     }
96    
97    
98     /*
99     * Deinitialization
100     */
101    
102     void SCSIExit(void)
103     {
104     // Close all devices
105     for (int i=0; i<8; i++) {
106     int fd = fds[i];
107     if (fd > 0)
108     close(fd);
109     }
110    
111     // Free buffer
112     if (buffer) {
113     free(buffer);
114     buffer = NULL;
115     }
116     }
117    
118    
119     /*
120     * Check if requested data size fits into buffer, allocate new buffer if needed
121     */
122    
123     static bool try_buffer(int size)
124     {
125     size += sizeof(struct sg_header) + 12;
126     if (size <= buffer_size)
127     return true;
128    
129     uint8 *new_buffer = (uint8 *)malloc(size);
130     if (new_buffer == NULL)
131     return false;
132     free(buffer);
133     buffer = new_buffer;
134     buffer_size = size;
135     return true;
136     }
137    
138    
139     /*
140     * Set SCSI command to be sent by scsi_send_cmd()
141     */
142    
143     void scsi_set_cmd(int cmd_length, uint8 *cmd)
144     {
145     memcpy(the_cmd, cmd, the_cmd_len = cmd_length);
146     }
147    
148    
149     /*
150     * Check for presence of SCSI target
151     */
152    
153     bool scsi_is_target_present(int id)
154     {
155     return fds[id] > 0;
156     }
157    
158    
159     /*
160     * Set SCSI target (returns false on error)
161     */
162    
163     bool scsi_set_target(int id, int lun)
164     {
165     int new_fd = fds[id];
166     if (new_fd < 0)
167     return false;
168     if (new_fd != fd) {
169     // Clear autosense data
170     struct sg_header *h = (struct sg_header *)buffer;
171     h->sense_buffer[2] = 0;
172     }
173     fd = new_fd;
174     return true;
175     }
176    
177    
178     /*
179     * Send SCSI command to active target (scsi_set_command() must have been called),
180     * read/write data according to S/G table (returns false on error); timeout is in 1/60 sec
181     */
182    
183     bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
184     {
185     static int pack_id = 0;
186    
187     // Check if buffer is large enough, allocate new buffer if needed
188     if (!try_buffer(data_length)) {
189     char str[256];
190     sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
191     ErrorAlert(str);
192     return false;
193     }
194    
195     // Process S/G table when writing
196     if (!reading) {
197     D(bug(" writing to buffer\n"));
198     uint8 *buffer_ptr = buffer + sizeof(struct sg_header) + the_cmd_len;
199     for (int i=0; i<sg_size; i++) {
200     uint32 len = sg_len[i];
201     D(bug(" %d bytes from %08lx\n", len, sg_ptr[i]));
202     memcpy(buffer_ptr, sg_ptr[i], len);
203     buffer_ptr += len;
204     }
205     }
206    
207     // Request Sense and autosense data valid?
208     struct sg_header *h = (struct sg_header *)buffer;
209     int res;
210     if (the_cmd[0] == 0x03 && (h->sense_buffer[2] & 0x0f)) {
211    
212     // Yes, fake command
213     D(bug(" autosense\n"));
214     memcpy(buffer + sizeof(struct sg_header), h->sense_buffer, 16);
215     res = 0;
216     *stat = 0;
217    
218     } else {
219    
220     // No, send regular command
221     int to = timeout * HZ / 60;
222     ioctl(fd, SG_SET_TIMEOUT, &to);
223     D(bug(" sending command, length %d\n", data_length));
224     int request_size, reply_size;
225     if (reading) {
226     h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len;
227     h->reply_len = reply_size = sizeof(struct sg_header) + data_length;
228     } else {
229     h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len + data_length;
230     h->reply_len = reply_size = sizeof(struct sg_header);
231     }
232     h->pack_id = pack_id++;
233     h->result = 0;
234     h->twelve_byte = (the_cmd_len == 12);
235     h->sense_buffer[2] = 0;
236     memcpy(buffer + sizeof(struct sg_header), the_cmd, the_cmd_len);
237     res = write(fd, buffer, request_size);
238     D(bug(" request sent, actual %d, result %d\n", res, h->result));
239     if (res >= 0) {
240     res = read(fd, buffer, reply_size);
241     D(bug(" reply read, actual %d, result %d\n", res, h->result));
242     }
243     if (h->sense_buffer[2] & 0x0f)
244     *stat = 2; // Check condition
245     else
246     *stat = 0; // No error
247     }
248    
249     // Process S/G table when reading
250     if (reading && h->result == 0) {
251     D(bug(" reading from buffer\n"));
252     uint8 *buffer_ptr = buffer + sizeof(struct sg_header);
253     for (int i=0; i<sg_size; i++) {
254     uint32 len = sg_len[i];
255     D(bug(" %d bytes to %08lx\n", len, sg_ptr[i]));
256     memcpy(sg_ptr[i], buffer_ptr, len);
257     buffer_ptr += len;
258     }
259     }
260     return res >= 0;
261     }