Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / modes.c
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
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
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
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 }