ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Linux/scsi_linux.cpp
Revision: 1.4
Committed: 2001-02-02T20:52:58Z (23 years, 5 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-17022001, snapshot-29052001, release-0_9-1
Changes since 1.3: +1 -1 lines
Log Message:
- bumped version number to 0.9
- updated copyright dates

File Contents

# Content
1 /*
2 * scsi_linux.cpp - SCSI Manager, Linux specific stuff
3 *
4 * Basilisk II (C) 1997-2001 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(uint32 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 }