1 /* @(#)wm_packet.c	1.31 10/12/19 Copyright 1995, 1997, 2001-2010 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)wm_packet.c	1.31 10/12/19 Copyright 1995, 1997, 2001-2010 J. Schilling";
6 #endif
7 /*
8  *	CDR write method abtraction layer
9  *	packet writing intercace routines
10  *
11  *	Copyright (c) 1995, 1997, 2001-2010 J. Schilling
12  */
13 /*
14  * The contents of this file are subject to the terms of the
15  * Common Development and Distribution License, Version 1.0 only
16  * (the "License").  You may not use this file except in compliance
17  * with the License.
18  *
19  * See the file CDDL.Schily.txt in this distribution for details.
20  * A copy of the CDDL is also available via the Internet at
21  * http://www.opensource.org/licenses/cddl1.txt
22  *
23  * When distributing Covered Code, include this CDDL HEADER in each
24  * file and include the License file CDDL.Schily.txt from this distribution.
25  */
26 
27 #include <schily/mconfig.h>
28 #include <schily/stdio.h>
29 #include <schily/stdlib.h>
30 #include <schily/unistd.h>
31 #include <schily/time.h>
32 #include <schily/standard.h>
33 #include <schily/utypes.h>
34 #include <schily/schily.h>
35 #include <schily/nlsdefs.h>
36 
37 #include <scg/scsitransp.h>
38 #include "cdrecord.h"
39 #include "xio.h"
40 
41 extern	int	debug;
42 extern	int	verbose;
43 extern	int	lverbose;
44 
45 extern	char	*buf;			/* The transfer buffer */
46 
47 EXPORT	int	write_packet_data __PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
48 
49 EXPORT int
write_packet_data(scgp,dp,trackp)50 write_packet_data(scgp, dp, trackp)
51 	SCSI	*scgp;
52 	cdr_t	*dp;
53 	track_t	*trackp;
54 {
55 	int	track = trackp->trackno;
56 	int	f = -1;
57 	int	isaudio;
58 	long	startsec;
59 	Llong	bytes_read = 0;
60 	Llong	bytes	= 0;
61 	Llong	savbytes = 0;
62 	int	count;
63 	Llong	tracksize;
64 	int	secsize;
65 	int	secspt;
66 	int	bytespt;
67 	int	bytes_to_read;
68 	long	amount;
69 	int	pad;
70 	int	retried;
71 	long	nextblock;
72 	BOOL	neednl	= FALSE;
73 	BOOL	islast	= FALSE;
74 	char	*bp	= buf;
75 	struct timeval tlast;
76 	struct timeval tcur;
77 	float	secsps = 75.0;
78 long bsize;
79 long bfree;
80 #define	BCAP
81 #ifdef	BCAP
82 int per = 0;
83 #ifdef	XBCAP
84 int oper = -1;
85 #endif
86 #endif
87 
88 	if (dp->cdr_dstat->ds_flags & DSF_DVD)
89 		secsps = 676.27;
90 	if (dp->cdr_dstat->ds_flags & DSF_BD)
91 		secsps = 2195.07;
92 
93 	scgp->silent++;
94 	if ((*dp->cdr_buffer_cap)(scgp, &bsize, &bfree) < 0)
95 		bsize = -1L;
96 	if (bsize == 0)		/* If we have no (known) buffer, we cannot */
97 		bsize = -1L;	/* retrieve the buffer fill ratio	   */
98 	else
99 		dp->cdr_dstat->ds_buflow = 0;
100 	scgp->silent--;
101 
102 	if (trackp->xfp != NULL)
103 		f = xfileno(trackp->xfp);
104 
105 	isaudio = is_audio(trackp);
106 	tracksize = trackp->tracksize;
107 	startsec = trackp->trackstart;
108 
109 	secsize = trackp->secsize;
110 	secspt = trackp->secspt;
111 	bytespt = secsize * secspt;
112 
113 	pad = !isaudio && is_pad(trackp);	/* Pad only data tracks */
114 
115 	if (debug) {
116 		printf(_("secsize:%d secspt:%d bytespt:%d audio:%d pad:%d\n"),
117 			secsize, secspt, bytespt, isaudio, pad);
118 	}
119 
120 	if (lverbose) {
121 		if (tracksize > 0)
122 			printf(_("\rTrack %02d:    0 of %4lld MB written."),
123 				track, tracksize >> 20);
124 		else
125 			printf(_("\rTrack %02d:    0 MB written."), track);
126 		flush();
127 		neednl = TRUE;
128 	}
129 
130 	gettimeofday(&tlast, (struct timezone *)0);
131 	do {
132 		bytes_to_read = bytespt;
133 		if (tracksize > 0) {
134 			if ((tracksize - bytes_read) > bytespt)
135 				bytes_to_read = bytespt;
136 			else
137 				bytes_to_read = tracksize - bytes_read;
138 		}
139 					/* XXX next wr addr ??? */
140 		count = get_buf(f, trackp, startsec, &bp, bytes_to_read);
141 		if (count < 0)
142 			comerr(_("read error on input file\n"));
143 		if (count == 0)
144 			break;
145 		bytes_read += count;
146 		if (tracksize >= 0 && bytes_read >= tracksize) {
147 			count -= bytes_read - tracksize;
148 			if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
149 				islast = TRUE;
150 		}
151 
152 		if (count < bytespt) {
153 			if (debug) {
154 				printf(_("\nNOTICE: reducing block size for last record.\n"));
155 				neednl = FALSE;
156 			}
157 
158 			if ((amount = count % secsize) != 0) {
159 				amount = secsize - amount;
160 				fillbytes(&bp[count], amount, '\0');
161 				count += amount;
162 				printf(_("\nWARNING: padding up to secsize.\n"));
163 				neednl = FALSE;
164 			}
165 			if (is_packet(trackp) && trackp->pktsize > 0) {
166 				if (count < bytespt) {
167 					amount = bytespt - count;
168 					count += amount;
169 					printf(_("\nWARNING: padding remainder of packet.\n"));
170 					neednl = FALSE;
171 				}
172 			}
173 			bytespt = count;
174 			secspt = count / secsize;
175 			if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
176 				islast = TRUE;
177 		}
178 
179 		retried = 0;
180 		retry:
181 		/* XXX Fixed-packet writes can be very slow*/
182 		if (is_packet(trackp) && trackp->pktsize > 0)
183 			scg_settimeout(scgp, 100);
184 		/* XXX */
185 		if (is_packet(trackp) && trackp->pktsize == 0) {
186 			if ((*dp->cdr_next_wr_address)(scgp, trackp, &nextblock) == 0) {
187 				/*
188 				 * Some drives (e.g. Ricoh MPS6201S) do not
189 				 * increment the Next Writable Address value to
190 				 * point to the beginning of a new packet if
191 				 * their write buffer has underflowed.
192 				 */
193 				if (retried && nextblock == startsec) {
194 					startsec += 7;
195 				} else {
196 					startsec = nextblock;
197 				}
198 			}
199 		}
200 
201 		amount = write_secs(scgp, dp, bp, startsec, bytespt, secspt, islast);
202 		if (amount < 0) {
203 			if (is_packet(trackp) && trackp->pktsize == 0 && !retried) {
204 				printf(_("%swrite track data: error after %lld bytes, retry with new packet\n"),
205 					neednl?"\n":"", bytes);
206 				retried = 1;
207 				neednl = FALSE;
208 				goto retry;
209 			}
210 			printf(_("%swrite track data: error after %lld bytes\n"),
211 							neednl?"\n":"", bytes);
212 			return (-1);
213 		}
214 		bytes += amount;
215 		startsec += amount / secsize;
216 
217 		if (lverbose && (bytes >= (savbytes + 0x100000))) {
218 			int	fper;
219 			int	nsecs = (bytes - savbytes) / secsize;
220 			float	fspeed;
221 
222 			gettimeofday(&tcur, (struct timezone *)0);
223 			printf(_("\rTrack %02d: %4lld"), track, bytes >> 20);
224 			if (tracksize > 0)
225 				printf(_(" of %4lld MB"), tracksize >> 20);
226 			else
227 				printf(" MB");
228 			printf(_(" written"));
229 			fper = fifo_percent(TRUE);
230 			if (fper >= 0)
231 				printf(" (fifo %3d%%)", fper);
232 #ifdef	BCAP
233 			if (bsize > 0) {			/* buffer size known */
234 				scgp->silent++;
235 				per = (*dp->cdr_buffer_cap)(scgp, (long *)0, &bfree);
236 				scgp->silent--;
237 				if (per >= 0) {
238 					per = 100*(bsize - bfree) / bsize;
239 					if (per < 5)
240 						dp->cdr_dstat->ds_buflow++;
241 					if (per < (int)dp->cdr_dstat->ds_minbuf &&
242 					    (startsec*secsize) > bsize) {
243 						dp->cdr_dstat->ds_minbuf = per;
244 					}
245 					printf(" [buf %3d%%]", per);
246 #ifdef	BCAPDBG
247 					printf(" %3ld %3ld", bsize >> 10, bfree >> 10);
248 #endif
249 				}
250 			}
251 #endif
252 
253 			tlast.tv_sec = tcur.tv_sec - tlast.tv_sec;
254 			tlast.tv_usec = tcur.tv_usec - tlast.tv_usec;
255 			while (tlast.tv_usec < 0) {
256 				tlast.tv_usec += 1000000;
257 				tlast.tv_sec -= 1;
258 			}
259 			fspeed = (nsecs / secsps) /
260 				(tlast.tv_sec * 1.0 + tlast.tv_usec * 0.000001);
261 			if (fspeed > 999.0)
262 				fspeed = 999.0;
263 			printf(" %5.1fx", fspeed);
264 			printf(".");
265 			savbytes = (bytes >> 20) << 20;
266 			flush();
267 			neednl = TRUE;
268 			tlast = tcur;
269 		}
270 	} while (tracksize < 0 || bytes_read < tracksize);
271 
272 	if ((bytes / secsize) < 300) {
273 		if ((trackp->padsecs + (bytes / secsize)) < 300)
274 			trackp->padsecs = 300 - (bytes / secsize);
275 	}
276 	if (trackp->padsecs > 0) {
277 		Llong	padbytes;
278 
279 		/*
280 		 * pad_track() is based on secsize. Compute the amount of bytes
281 		 * assumed by pad_track().
282 		 */
283 		padbytes = (Llong)trackp->padsecs * secsize;
284 
285 		if (neednl) {
286 			printf("\n");
287 			neednl = FALSE;
288 		}
289 		if ((padbytes >> 20) > 0) {
290 			neednl = TRUE;
291 		} else if (lverbose) {
292 			printf(_("Track %02d: writing %3lld KB of pad data.\n"),
293 					track, (Llong)(padbytes >> 10));
294 			neednl = FALSE;
295 		}
296 		pad_track(scgp, dp, trackp, startsec, padbytes,
297 					TRUE, &savbytes);
298 		bytes += savbytes;
299 		startsec += savbytes / secsize;
300 	}
301 	printf(_("%sTrack %02d: Total bytes read/written: %lld/%lld (%lld sectors).\n"),
302 		neednl?"\n":"", track, bytes_read, bytes, bytes/secsize);
303 	return (0);
304 }
305