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