1 /*
2 * This file has been modified for the cdrkit suite.
3 *
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
6 *
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
10 *
11 */
12
13 /* @(#)modes.c 1.25 04/03/02 Copyright 1988, 1997-2001, 2004 J. Schilling */
14 /*
15 * SCSI mode page handling
16 *
17 * Copyright (c) 1988, 1997-2001, 2004 J. Schilling
18 */
19 /*
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 */
33
34 #include <mconfig.h>
35 #include <utypes.h>
36 #include <standard.h>
37 #include <schily.h>
38 #include <usal/usalcmd.h>
39 #include <usal/scsireg.h>
40 #include <usal/scsitransp.h>
41
42 #include "wodim.h"
43
44 int scsi_compliant;
45
46 static BOOL has_mode_page(SCSI *usalp, int page, char *pagename, int *lenp);
47 BOOL get_mode_params(SCSI *usalp, int page, char *pagename, Uchar *modep,
48 Uchar *cmodep, Uchar *dmodep, Uchar *smodep, int *lenp);
49 BOOL set_mode_params(SCSI *usalp, char *pagename, Uchar *modep, int len,
50 int save, int secsize);
51
52 #define XXX
53
54 #ifdef XXX
55 static BOOL
has_mode_page(SCSI * usalp,int page,char * pagename,int * lenp)56 has_mode_page(SCSI *usalp, int page, char *pagename, int *lenp)
57 {
58 Uchar mode[0x100];
59 int hdlen;
60 int len = 1; /* Nach SCSI Norm */
61 int try = 0;
62 struct scsi_mode_page_header *mp;
63
64 /*
65 * ATAPI drives (used e.g. by IOMEGA) from y2k have the worst firmware
66 * I've seen. They create DMA buffer overruns if we request less than
67 * 3 bytes with 6 byte mode sense which equals 4 byte with 10 byte mode
68 * sense. In order to prevent repeated bus resets, we remember this
69 * bug.
70 *
71 * IOMEGA claims that they are using Philips clone drives but a Philips
72 * drive I own does not have the problem.
73 */
74 if ((usalp->dflags & DRF_MODE_DMA_OVR) != 0)
75 len = sizeof (struct scsi_mode_header);
76 again:
77 fillbytes((caddr_t)mode, sizeof (mode), '\0');
78 if (lenp)
79 *lenp = 0;
80
81 usalp->silent++;
82 (void) unit_ready(usalp);
83 /* Maxoptix bringt Aborted cmd 0x0B mit code 0x4E (overlapping cmds)*/
84
85 /*
86 * The Matsushita CW-7502 will sometimes deliver a zeroed
87 * mode page 2A if "Page n default" is used instead of "current".
88 */
89 if (mode_sense(usalp, mode, len, page, 0) < 0) { /* Page n current */
90 usalp->silent--;
91 if (len < (int)sizeof (struct scsi_mode_header) && try == 0) {
92 len = sizeof (struct scsi_mode_header);
93 goto again;
94 }
95 return (FALSE);
96 } else {
97 if (len > 1 && try == 0) {
98 /*
99 * If we come here, we got a hard failure with the
100 * fist try. Remember this (IOMEGA USB) firmware bug.
101 */
102 if ((usalp->dflags & DRF_MODE_DMA_OVR) == 0) {
103 /* XXX if (!nowarn) */
104 errmsgno(EX_BAD,
105 "Warning: controller creates hard SCSI failure when retrieving %s page.\n",
106 pagename);
107 usalp->dflags |= DRF_MODE_DMA_OVR;
108 }
109 }
110 len = ((struct scsi_mode_header *)mode)->sense_data_len + 1;
111 }
112 /*
113 * ATAPI drives as used by IOMEGA may receive a SCSI bus device reset
114 * in between these two mode sense commands.
115 */
116 (void) unit_ready(usalp);
117 if (mode_sense(usalp, mode, len, page, 0) < 0) { /* Page n current */
118 usalp->silent--;
119 return (FALSE);
120 }
121 usalp->silent--;
122
123 if (usalp->verbose)
124 usal_prbytes("Mode Sense Data", mode, len - usal_getresid(usalp));
125 hdlen = sizeof (struct scsi_mode_header) +
126 ((struct scsi_mode_header *)mode)->blockdesc_len;
127 mp = (struct scsi_mode_page_header *)(mode + hdlen);
128 if (usalp->verbose)
129 usal_prbytes("Mode Page Data", (Uchar *)mp, mp->p_len+2);
130
131 if (mp->p_len == 0) {
132 if (!scsi_compliant && try == 0) {
133 len = hdlen;
134 /*
135 * add sizeof page header (page # + len byte)
136 * (should normaly result in len == 14)
137 * this allowes to work with:
138 * Quantum Q210S (wants at least 13)
139 * MD2x (wants at least 4)
140 */
141 len += 2;
142 try++;
143 goto again;
144 }
145 /* XXX if (!nowarn) */
146 errmsgno(EX_BAD,
147 "Warning: controller returns zero sized %s page.\n",
148 pagename);
149 }
150 if (!scsi_compliant &&
151 (len < (int)(mp->p_len + hdlen + 2))) {
152 len = mp->p_len + hdlen + 2;
153
154 /* XXX if (!nowarn) */
155 errmsgno(EX_BAD,
156 "Warning: controller returns wrong size for %s page.\n",
157 pagename);
158 }
159 if (mp->p_code != page) {
160 /* XXX if (!nowarn) */
161 errmsgno(EX_BAD,
162 "Warning: controller returns wrong page %X for %s page (%X).\n",
163 mp->p_code, pagename, page);
164 return (FALSE);
165 }
166
167 if (lenp)
168 *lenp = len;
169 return (mp->p_len > 0);
170 }
171 #endif
172
173 BOOL
get_mode_params(SCSI * usalp,int page,char * pagename,Uchar * modep,Uchar * cmodep,Uchar * dmodep,Uchar * smodep,int * lenp)174 get_mode_params(SCSI *usalp, int page, char *pagename, Uchar *modep,
175 Uchar *cmodep, Uchar *dmodep, Uchar *smodep, int *lenp)
176 {
177 int len;
178 BOOL ret = TRUE;
179
180 #ifdef XXX
181 if (lenp)
182 *lenp = 0;
183 if (!has_mode_page(usalp, page, pagename, &len)) {
184 if (!usalp->silent) errmsgno(EX_BAD,
185 "Warning: controller does not support %s page.\n",
186 pagename);
187 return (FALSE);
188 }
189 if (lenp)
190 *lenp = len;
191 #else
192 if (lenp == 0)
193 len = 0xFF;
194 #endif
195
196 if (modep) {
197 fillbytes(modep, 0x100, '\0');
198 usalp->silent++;
199 (void) unit_ready(usalp);
200 usalp->silent--;
201 if (mode_sense(usalp, modep, len, page, 0) < 0) { /* Page x current */
202 errmsgno(EX_BAD, "Cannot get %s data.\n", pagename);
203 ret = FALSE;
204 } else if (usalp->verbose) {
205 usal_prbytes("Mode Sense Data", modep, len - usal_getresid(usalp));
206 }
207 }
208
209 if (cmodep) {
210 fillbytes(cmodep, 0x100, '\0');
211 usalp->silent++;
212 (void) unit_ready(usalp);
213 usalp->silent--;
214 if (mode_sense(usalp, cmodep, len, page, 1) < 0) { /* Page x change */
215 errmsgno(EX_BAD, "Cannot get %s mask.\n", pagename);
216 ret = FALSE;
217 } else if (usalp->verbose) {
218 usal_prbytes("Mode Sense Data", cmodep, len - usal_getresid(usalp));
219 }
220 }
221
222 if (dmodep) {
223 fillbytes(dmodep, 0x100, '\0');
224 usalp->silent++;
225 (void) unit_ready(usalp);
226 usalp->silent--;
227 if (mode_sense(usalp, dmodep, len, page, 2) < 0) { /* Page x default */
228 errmsgno(EX_BAD, "Cannot get default %s data.\n",
229 pagename);
230 ret = FALSE;
231 } else if (usalp->verbose) {
232 usal_prbytes("Mode Sense Data", dmodep, len - usal_getresid(usalp));
233 }
234 }
235
236 if (smodep) {
237 fillbytes(smodep, 0x100, '\0');
238 usalp->silent++;
239 (void) unit_ready(usalp);
240 usalp->silent--;
241 if (mode_sense(usalp, smodep, len, page, 3) < 0) { /* Page x saved */
242 errmsgno(EX_BAD, "Cannot get saved %s data.\n", pagename);
243 ret = FALSE;
244 } else if (usalp->verbose) {
245 usal_prbytes("Mode Sense Data", smodep, len - usal_getresid(usalp));
246 }
247 }
248
249 return (ret);
250 }
251
252 BOOL
set_mode_params(SCSI * usalp,char * pagename,Uchar * modep,int len,int save,int secsize)253 set_mode_params(SCSI *usalp, char *pagename, Uchar *modep, int len, int save,
254 int secsize)
255 {
256 int i;
257
258 ((struct scsi_modesel_header *)modep)->sense_data_len = 0;
259 ((struct scsi_modesel_header *)modep)->res2 = 0;
260
261 i = ((struct scsi_mode_header *)modep)->blockdesc_len;
262 if (i > 0) {
263 i_to_3_byte(
264 ((struct scsi_mode_data *)modep)->blockdesc.nlblock,
265 0);
266 if (secsize >= 0)
267 i_to_3_byte(((struct scsi_mode_data *)modep)->blockdesc.lblen,
268 secsize);
269 }
270
271 usalp->silent++;
272 (void) unit_ready(usalp);
273 usalp->silent--;
274 if (save == 0 || mode_select(usalp, modep, len, save, usalp->inq->data_format >= 2) < 0) {
275 usalp->silent++;
276 (void) unit_ready(usalp);
277 usalp->silent--;
278 if (mode_select(usalp, modep, len, 0, usalp->inq->data_format >= 2) < 0) {
279 if (usalp->silent == 0) {
280 errmsgno(EX_BAD,
281 "Warning: using default %s data.\n",
282 pagename);
283 usal_prbytes("Mode Select Data", modep, len);
284 }
285 return (FALSE);
286 }
287 }
288 return (TRUE);
289 }
290