1 /*
2 * toscsi.c
3 *
4 * SCSI access functions for tosha.
5 *
6 * Oliver Fromme <olli@fromme.com>
7 *
8 * Copyright (C) 1997,1998,1999
9 * Oliver Fromme. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the author nor the names of any co-contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY OLIVER FROMME AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL OLIVER FROMME OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)$Id: toscsi.c,v 1.3 1999/01/01 23:32:01 olli Exp $
36 */
37
38 static const char cvsid[]
39 = "@(#)$Id: toscsi.c,v 1.3 1999/01/01 23:32:01 olli Exp $";
40
41 #include "utils.h"
42 #include "global.h"
43 #include "toscsi.h"
44
45 ulong readsectors = 0; /* total number of sectors we've already read */
46
47 /*
48 * Send a "simple" request to the SCSI subsystem.
49 * See the scsi(3) manual page for more information.
50 */
51
52 int
toscsi_request(toscsi_handle * hdl,ulong size,ulong flags,char * cmd)53 toscsi_request (toscsi_handle *hdl, ulong size, ulong flags, char *cmd)
54 {
55 int result;
56
57 #ifdef CAM
58 bzero (&(&hdl->ccb->ccb_h)[1], sizeof(struct ccb_scsiio));
59 csio_build (&hdl->ccb->csio,
60 /* data_ptr */ (u_int8_t *) buf,
61 /* dxfer_len */ size,
62 /* flags */ flags | CAM_PASS_ERR_RECOVER,
63 /* retry_count */ 3,
64 /* timeout */ 10000,
65 /* cmd_spec */ cmd);
66 if ((result = cam_send_ccb(hdl->cam_dev, hdl->ccb)) < 0) {
67 perror ("error sending SCSI command");
68 cam_freeccb (hdl->ccb);
69 cam_close_device (hdl->cam_dev);
70 exit (1);
71 }
72 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
73 fprintf (stderr, "error returned from SCSI command:\n");
74 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) ==
75 CAM_SCSI_STATUS_ERROR)
76 scsi_sense_print (hdl->cam_dev,
77 &hdl->ccb->csio, stderr);
78 else
79 fprintf (stderr, "ccb->ccb_h.status == %d\n",
80 hdl->ccb->ccb_h.status);
81 exit (1);
82 }
83 #else /* !CAM */
84 scsireq_reset (hdl->sreq);
85 hdl->sreq->timeout = 10000;
86 scsireq_build (hdl->sreq, size, (char *) buf, flags, cmd);
87 result = scsireq_enter(hdl->scsifd, hdl->sreq);
88 # ifndef DEBUG
89 if (SCSIREQ_ERROR (hdl->sreq))
90 # endif
91 scsi_debug (stderr, result, hdl->sreq);
92 #endif /* !CAM */
93
94 return result;
95 }
96
97 static void
print_progress(long long trackstart,long long thistime,int num,int done)98 print_progress (long long trackstart, long long thistime, int num, int done)
99 {
100 int trackdone, totaldone;
101 long long duration;
102 ulong trackleft, totalleft;
103
104 totaldone = (readsectors * 100) / totalsectors;
105 duration = (long long) thistime - starttime;
106 totalleft = ((duration * totalsectors) / readsectors
107 - duration + 500000) / 1000000;
108 if (tracklistsize > 1) {
109 trackdone = ((ulong) done * 100) / num;
110 duration = (long long) thistime - trackstart;
111 trackleft = ((duration * num) / done - duration + 500000)
112 / 1000000;
113 fprintf (stderr, " track:%3d%% done,%2d:%02d to go,",
114 trackdone, (int) trackleft / 60, (int) trackleft % 60);
115 }
116 fprintf (stderr, " total:%3d%% done,%3d:%02d to go\r",
117 totaldone, (int) totalleft / 60, (int) totalleft % 60);
118 }
119
120 /*
121 * Read sectors from "start" to "endpp" - 1, and output
122 * them to the file descriptor "outfd".
123 */
124
125 int
toscsi_readsectors(toscsi_handle * hdl,int start,int endpp,int outfd)126 toscsi_readsectors (toscsi_handle *hdl, int start, int endpp, int outfd)
127 {
128 long long trackstarttime, lasttime, thistime;
129 int sec, secread, result;
130 int fcount = 0;
131
132 get_time (&trackstarttime);
133 lasttime = trackstarttime;
134 for (sec = start; sec < endpp; sec += secread) {
135 if ((secread = sectorsperbuf) > endpp - sec)
136 secread = endpp - sec;
137
138 #ifdef CAM
139 if (readcmd == 0xd8)
140 csio_build (&hdl->ccb->csio,
141 /* data_ptr */ (u_int8_t *) buf,
142 /* dxfer_len */ SECTORSIZE * secread,
143 /* flags */ CAM_DIR_IN |
144 CAM_PASS_ERR_RECOVER,
145 /* retries */ 3,
146 /* timeout */ 10000,
147 /* cmd_spec */ "v 0 0 v:i3 0 0 0 v 0 0",
148 readcmd, sec, secread);
149 else
150 csio_build (&hdl->ccb->csio,
151 /* data_ptr */ (u_int8_t *) buf,
152 /* dxfer_len */ SECTORSIZE * secread,
153 /* flags */ CAM_DIR_IN |
154 CAM_PASS_ERR_RECOVER,
155 /* retries */ 3,
156 /* timeout */ 10000,
157 /* cmd_spec */ "v 0 0 v:i3 0 0 v 0",
158 readcmd, sec, secread);
159 if ((result = cam_send_ccb(hdl->cam_dev, hdl->ccb)) < 0) {
160 perror ("error sending CD-DA read command");
161 cam_freeccb (hdl->ccb);
162 cam_close_device (hdl->cam_dev);
163 exit (1);
164 }
165 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
166 fprintf(stderr,
167 "error returned from CD-DA read command:\n");
168 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) ==
169 CAM_SCSI_STATUS_ERROR)
170 scsi_sense_print (hdl->cam_dev,
171 &hdl->ccb->csio, stderr);
172 else
173 fprintf (stderr, "ccb->ccb_h.status == %d\n",
174 hdl->ccb->ccb_h.status);
175 exit (1);
176 }
177 #else /* !CAM */
178 scsireq_reset (hdl->sreq);
179 hdl->sreq->timeout = 10000;
180 if (readcmd == 0xd8)
181 scsireq_build (hdl->sreq, SECTORSIZE * secread,
182 (char *) buf, SCCMD_READ,
183 "v 0 0 v:i3 0 0 0 v 0 0",
184 readcmd, sec, secread);
185 else
186 scsireq_build (hdl->sreq, SECTORSIZE * secread,
187 (char *) buf, SCCMD_READ,
188 "v 0 0 v:i3 0 0 v 0", readcmd,
189 sec, secread);
190 result = scsireq_enter (hdl->scsifd, hdl->sreq);
191 # ifndef DEBUG
192 if (SCSIREQ_ERROR (hdl->sreq))
193 # endif
194 scsi_debug (stderr, result, hdl->sreq);
195 #endif /* !CAM */
196 if (byteswap) {
197 int j, num = SECTORSIZE * secread;
198 byte t;
199 for (j = 0; j < num; j += 2) {
200 t = buf[j];
201 buf[j] = buf[j + 1];
202 buf[j + 1] = t;
203 }
204 }
205 write (outfd, buf, SECTORSIZE * secread);
206 readsectors += secread;
207 if (verbose && (fcount += secread) > 99) {
208 fcount = 0;
209 get_time (&thistime);
210 if (lasttime + 2000000 < thistime) {
211 print_progress (trackstarttime, thistime,
212 endpp - start, sec - start);
213 lasttime = thistime;
214 }
215 }
216 }
217 return TRUE;
218 }
219
220 /*
221 * Read one data sector and return the mode byte.
222 */
223
224 int
toscsi_readmode(toscsi_handle * hdl,int sector)225 toscsi_readmode (toscsi_handle *hdl, int sector)
226 {
227 int result;
228
229 #ifdef CAM
230 csio_build (&hdl->ccb->csio,
231 /* data_ptr */ (u_int8_t *) buf,
232 /* dxfer_len */ SECTORSIZE * 1,
233 /* flags */ CAM_DIR_IN |
234 CAM_PASS_ERR_RECOVER,
235 /* retries */ 3,
236 /* timeout */ 10000,
237 /* cmd_spec */ "v 0 0 v:i3 0 0 v 0",
238 0x28, sector, 1);
239 if ((result = cam_send_ccb(hdl->cam_dev, hdl->ccb)) < 0) {
240 perror ("error sending CD-ROM read command");
241 cam_freeccb (hdl->ccb);
242 cam_close_device (hdl->cam_dev);
243 exit (1);
244 }
245 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
246 fprintf(stderr,
247 "error returned from CD-ROM read command:\n");
248 if ((hdl->ccb->ccb_h.status & CAM_STATUS_MASK) ==
249 CAM_SCSI_STATUS_ERROR)
250 scsi_sense_print (hdl->cam_dev,
251 &hdl->ccb->csio, stderr);
252 else
253 fprintf (stderr, "ccb->ccb_h.status == %d\n",
254 hdl->ccb->ccb_h.status);
255 exit (1);
256 }
257 #else /* !CAM */
258 scsireq_reset (hdl->sreq);
259 hdl->sreq->timeout = 10000;
260 scsireq_build (hdl->sreq, SECTORSIZE * 1,
261 (char *) buf, SCCMD_READ,
262 "v 0 0 v:i3 0 0 v 0", 0x28, sector, 1);
263 result = scsireq_enter (hdl->scsifd, hdl->sreq);
264 # ifndef DEBUG
265 if (SCSIREQ_ERROR (hdl->sreq))
266 # endif
267 scsi_debug (stderr, result, hdl->sreq);
268 #endif /* !CAM */
269 return buf[15];
270 }
271
272 toscsi_handle *
toscsi_open(const char * devname)273 toscsi_open (const char *devname)
274 {
275 toscsi_handle *hdl;
276
277 if (!(hdl = (toscsi_handle *) malloc(sizeof(toscsi_handle))))
278 out_of_memory();
279
280 #ifdef CAM
281 if (!(hdl->cam_dev = cam_open_device(devname, O_RDWR))) {
282 fprintf (stderr, "%s: %s\n", me, cam_errbuf);
283 exit (1);
284 }
285 if (!(hdl->ccb = cam_getccb(hdl->cam_dev))) {
286 fprintf (stderr, "%s: couldn't allocate CCB\n", me);
287 cam_close_device (hdl->cam_dev);
288 exit (1);
289 }
290 #else /* !CAM */
291 if ((hdl->scsifd = scsi_open(devname, O_RDWR)) < 0)
292 die (devname);
293 if (!(hdl->sreq = scsireq_new())) {
294 fprintf (stderr, "%s: scsireq_new(): Out of memory.\n", me);
295 exit (1);
296 }
297 #endif /* !CAM */
298
299 return hdl;
300 }
301
302 void
toscsi_close(toscsi_handle * hdl)303 toscsi_close (toscsi_handle *hdl)
304 {
305 #ifdef CAM
306 cam_close_device(hdl->cam_dev);
307 #else /* !CAM */
308 close (hdl->scsifd);
309 #endif /* !CAM */
310 }
311
312 /* EOF */
313