1 /* @(#)modes.c 1.29 09/07/10 Copyright 1988, 1997-2001, 2004-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)modes.c 1.29 09/07/10 Copyright 1988, 1997-2001, 2004-2009 J. Schilling";
6 #endif
7 /*
8 * SCSI mode page handling
9 *
10 * Copyright (c) 1988, 1997-2001, 2004-2009 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/utypes.h>
27 #include <schily/standard.h>
28 #include <schily/schily.h>
29 #include <scg/scgcmd.h>
30 #include <scg/scsireg.h>
31 #include <scg/scsitransp.h>
32
33 #include "libscgcmd.h"
34
35 EXPORT int scsi_compliant;
36
37 LOCAL BOOL has_mode_page __PR((SCSI *scgp, int page, char *pagename, int *lenp));
38 EXPORT BOOL get_mode_params __PR((SCSI *scgp, int page, char *pagename,
39 Uchar *modep, Uchar *cmodep,
40 Uchar *dmodep, Uchar *smodep,
41 int *lenp));
42 EXPORT BOOL set_mode_params __PR((SCSI *scgp, char *pagename, Uchar *modep,
43 int len, int save, int secsize));
44
45 #define XXX
46
47 #ifdef XXX
48 LOCAL BOOL
has_mode_page(scgp,page,pagename,lenp)49 has_mode_page(scgp, page, pagename, lenp)
50 SCSI *scgp;
51 int page;
52 char *pagename;
53 int *lenp;
54 {
55 Uchar mode[0x100];
56 int hdlen;
57 int len = 1; /* Nach SCSI Norm */
58 int try = 0;
59 struct scsi_mode_page_header *mp;
60
61 /*
62 * ATAPI drives (used e.g. by IOMEGA) from y2k have the worst firmware
63 * I've seen. They create DMA buffer overruns if we request less than
64 * 3 bytes with 6 byte mode sense which equals 4 byte with 10 byte mode
65 * sense. In order to prevent repeated bus resets, we remember this
66 * bug.
67 *
68 * IOMEGA claims that they are using Philips clone drives but a Philips
69 * drive I own does not have the problem.
70 */
71 if ((scgp->dflags & DRF_MODE_DMA_OVR) != 0)
72 len = sizeof (struct scsi_mode_header);
73 again:
74 fillbytes((caddr_t)mode, sizeof (mode), '\0');
75 if (lenp)
76 *lenp = 0;
77
78 scgp->silent++;
79 (void) unit_ready(scgp);
80 /* Maxoptix bringt Aborted cmd 0x0B mit code 0x4E (overlapping cmds)*/
81
82 /*
83 * The Matsushita CW-7502 will sometimes deliver a zeroed
84 * mode page 2A if "Page n default" is used instead of "current".
85 */
86 if (mode_sense(scgp, mode, len, page, 0) < 0) { /* Page n current */
87 scgp->silent--;
88 if (len < (int)sizeof (struct scsi_mode_header) && try == 0) {
89 len = sizeof (struct scsi_mode_header);
90 goto again;
91 }
92 return (FALSE);
93 } else {
94 if (len > 1 && try == 0) {
95 /*
96 * If we come here, we got a hard failure with the
97 * fist try. Remember this (IOMEGA USB) firmware bug.
98 */
99 if ((scgp->dflags & DRF_MODE_DMA_OVR) == 0) {
100 /* XXX if (!nowarn) */
101 errmsgno(EX_BAD,
102 "Warning: controller creates hard SCSI failure when retrieving %s page.\n",
103 pagename);
104 scgp->dflags |= DRF_MODE_DMA_OVR;
105 }
106 }
107 len = ((struct scsi_mode_header *)mode)->sense_data_len + 1;
108 }
109 /*
110 * ATAPI drives as used by IOMEGA may receive a SCSI bus device reset
111 * in between these two mode sense commands.
112 */
113 (void) unit_ready(scgp);
114 if (mode_sense(scgp, mode, len, page, 0) < 0) { /* Page n current */
115 scgp->silent--;
116 return (FALSE);
117 }
118 scgp->silent--;
119
120 if (scgp->verbose)
121 scg_prbytes("Mode Sense Data", mode, len - scg_getresid(scgp));
122 hdlen = sizeof (struct scsi_mode_header) +
123 ((struct scsi_mode_header *)mode)->blockdesc_len;
124 mp = (struct scsi_mode_page_header *)(mode + hdlen);
125 if (scgp->verbose)
126 scg_prbytes("Mode Page Data", (Uchar *)mp, mp->p_len+2);
127
128 if (mp->p_len == 0) {
129 if (!scsi_compliant && try == 0) {
130 len = hdlen;
131 /*
132 * add sizeof page header (page # + len byte)
133 * (should normaly result in len == 14)
134 * this allowes to work with:
135 * Quantum Q210S (wants at least 13)
136 * MD2x (wants at least 4)
137 */
138 len += 2;
139 try++;
140 goto again;
141 }
142 /* XXX if (!nowarn) */
143 errmsgno(EX_BAD,
144 "Warning: controller returns zero sized %s page.\n",
145 pagename);
146 }
147 if (!scsi_compliant &&
148 (len < (int)(mp->p_len + hdlen + 2))) {
149 len = mp->p_len + hdlen + 2;
150
151 /* XXX if (!nowarn) */
152 errmsgno(EX_BAD,
153 "Warning: controller returns wrong size for %s page.\n",
154 pagename);
155 }
156 if (mp->p_code != page) {
157 /* XXX if (!nowarn) */
158 errmsgno(EX_BAD,
159 "Warning: controller returns wrong page %X for %s page (%X).\n",
160 mp->p_code, pagename, page);
161 return (FALSE);
162 }
163
164 if (lenp)
165 *lenp = len;
166 return (mp->p_len > 0);
167 }
168 #endif
169
170 EXPORT BOOL
get_mode_params(scgp,page,pagename,modep,cmodep,dmodep,smodep,lenp)171 get_mode_params(scgp, page, pagename, modep, cmodep, dmodep, smodep, lenp)
172 SCSI *scgp;
173 int page;
174 char *pagename;
175 Uchar *modep;
176 Uchar *cmodep;
177 Uchar *dmodep;
178 Uchar *smodep;
179 int *lenp;
180 {
181 int len;
182 BOOL ret = TRUE;
183
184 #ifdef XXX
185 if (lenp)
186 *lenp = 0;
187 if (!has_mode_page(scgp, page, pagename, &len)) {
188 if (!scgp->silent) errmsgno(EX_BAD,
189 "Warning: controller does not support %s page.\n",
190 pagename);
191 return (FALSE);
192 }
193 if (lenp)
194 *lenp = len;
195 #else
196 if (lenp == 0)
197 len = 0xFF;
198 #endif
199
200 if (modep) {
201 fillbytes(modep, 0x100, '\0');
202 scgp->silent++;
203 (void) unit_ready(scgp);
204 scgp->silent--;
205 if (mode_sense(scgp, modep, len, page, 0) < 0) { /* Page x current */
206 errmsgno(EX_BAD, "Cannot get %s data.\n", pagename);
207 ret = FALSE;
208 } else if (scgp->verbose) {
209 scg_prbytes("Mode Sense Data", modep, len - scg_getresid(scgp));
210 }
211 }
212
213 if (cmodep) {
214 fillbytes(cmodep, 0x100, '\0');
215 scgp->silent++;
216 (void) unit_ready(scgp);
217 scgp->silent--;
218 if (mode_sense(scgp, cmodep, len, page, 1) < 0) { /* Page x change */
219 errmsgno(EX_BAD, "Cannot get %s mask.\n", pagename);
220 ret = FALSE;
221 } else if (scgp->verbose) {
222 scg_prbytes("Mode Sense Data", cmodep, len - scg_getresid(scgp));
223 }
224 }
225
226 if (dmodep) {
227 fillbytes(dmodep, 0x100, '\0');
228 scgp->silent++;
229 (void) unit_ready(scgp);
230 scgp->silent--;
231 if (mode_sense(scgp, dmodep, len, page, 2) < 0) { /* Page x default */
232 errmsgno(EX_BAD, "Cannot get default %s data.\n",
233 pagename);
234 ret = FALSE;
235 } else if (scgp->verbose) {
236 scg_prbytes("Mode Sense Data", dmodep, len - scg_getresid(scgp));
237 }
238 }
239
240 if (smodep) {
241 fillbytes(smodep, 0x100, '\0');
242 scgp->silent++;
243 (void) unit_ready(scgp);
244 scgp->silent--;
245 if (mode_sense(scgp, smodep, len, page, 3) < 0) { /* Page x saved */
246 errmsgno(EX_BAD, "Cannot get saved %s data.\n", pagename);
247 ret = FALSE;
248 } else if (scgp->verbose) {
249 scg_prbytes("Mode Sense Data", smodep, len - scg_getresid(scgp));
250 }
251 }
252
253 return (ret);
254 }
255
256 EXPORT BOOL
set_mode_params(scgp,pagename,modep,len,save,secsize)257 set_mode_params(scgp, pagename, modep, len, save, secsize)
258 SCSI *scgp;
259 char *pagename;
260 Uchar *modep;
261 int len;
262 int save;
263 int secsize;
264 {
265 int i;
266
267 ((struct scsi_modesel_header *)modep)->sense_data_len = 0;
268 ((struct scsi_modesel_header *)modep)->res2 = 0;
269
270 i = ((struct scsi_mode_header *)modep)->blockdesc_len;
271 if (i > 0) {
272 i_to_3_byte(
273 ((struct scsi_mode_data *)modep)->blockdesc.nlblock,
274 0);
275 if (secsize >= 0)
276 i_to_3_byte(((struct scsi_mode_data *)modep)->blockdesc.lblen,
277 secsize);
278 }
279
280 scgp->silent++;
281 (void) unit_ready(scgp);
282 scgp->silent--;
283 if (save == 0 || mode_select(scgp, modep, len, save, scgp->inq->data_format >= 2) < 0) {
284 scgp->silent++;
285 (void) unit_ready(scgp);
286 scgp->silent--;
287 if (mode_select(scgp, modep, len, 0, scgp->inq->data_format >= 2) < 0) {
288 if (scgp->silent == 0) {
289 errmsgno(EX_BAD,
290 "Warning: using default %s data.\n",
291 pagename);
292 scg_prbytes("Mode Select Data", modep, len);
293 }
294 return (FALSE);
295 }
296 }
297 return (TRUE);
298 }
299