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