1 /* @(#)modesense.c 1.158 09/07/10 Copyright 1995-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)modesense.c 1.158 09/07/10 Copyright 1995-2009 J. Schilling";
6 #endif
7 /*
8 * SCSI command functions for mode sense/mode select handling.
9 *
10 * Copyright (c) 1995-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/stdio.h>
27 #include <schily/standard.h>
28
29 #include <schily/utypes.h>
30 #include <schily/btorder.h>
31 #include <schily/intcvt.h>
32 #include <schily/schily.h>
33
34 #include <scg/scgcmd.h>
35 #include <scg/scsidefs.h>
36 #include <scg/scsireg.h>
37 #include <scg/scsitransp.h>
38
39 #include "libscgcmd.h"
40
41 EXPORT BOOL __is_atapi __PR((void));
42 EXPORT BOOL allow_atapi __PR((SCSI *scgp, BOOL new));
43 EXPORT int mode_select __PR((SCSI *scgp, Uchar *, int, int, int));
44 EXPORT int mode_sense __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf));
45 EXPORT int mode_select_sg0 __PR((SCSI *scgp, Uchar *, int, int, int));
46 EXPORT int mode_sense_sg0 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf));
47 EXPORT int mode_select_g0 __PR((SCSI *scgp, Uchar *, int, int, int));
48 EXPORT int mode_select_g1 __PR((SCSI *scgp, Uchar *, int, int, int));
49 EXPORT int mode_sense_g0 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf));
50 EXPORT int mode_sense_g1 __PR((SCSI *scgp, Uchar *dp, int cnt, int page, int pcf));
51
52 /*
53 * XXX First try to handle ATAPI:
54 * XXX ATAPI cannot handle SCSI 6 byte commands.
55 * XXX We try to simulate 6 byte mode sense/select.
56 */
57 LOCAL BOOL is_atapi;
58
59 EXPORT BOOL
__is_atapi()60 __is_atapi()
61 {
62 return (is_atapi);
63 }
64
65 EXPORT BOOL
allow_atapi(scgp,new)66 allow_atapi(scgp, new)
67 SCSI *scgp;
68 BOOL new;
69 {
70 BOOL old = is_atapi;
71 Uchar mode[256];
72
73 if (new == old)
74 return (old);
75
76 scgp->silent++;
77 /*
78 * If a bad drive has been reset before, we may need to fire up two
79 * test unit ready commands to clear status.
80 */
81 (void) unit_ready(scgp);
82 if (new &&
83 mode_sense_g1(scgp, mode, 8, 0x3F, 0) < 0) { /* All pages current */
84 new = FALSE;
85 }
86 scgp->silent--;
87
88 is_atapi = new;
89 return (old);
90 }
91
92 EXPORT int
mode_select(scgp,dp,cnt,smp,pf)93 mode_select(scgp, dp, cnt, smp, pf)
94 SCSI *scgp;
95 Uchar *dp;
96 int cnt;
97 int smp;
98 int pf;
99 {
100 if (is_atapi)
101 return (mode_select_sg0(scgp, dp, cnt, smp, pf));
102 return (mode_select_g0(scgp, dp, cnt, smp, pf));
103 }
104
105 EXPORT int
mode_sense(scgp,dp,cnt,page,pcf)106 mode_sense(scgp, dp, cnt, page, pcf)
107 SCSI *scgp;
108 Uchar *dp;
109 int cnt;
110 int page;
111 int pcf;
112 {
113 if (is_atapi)
114 return (mode_sense_sg0(scgp, dp, cnt, page, pcf));
115 return (mode_sense_g0(scgp, dp, cnt, page, pcf));
116 }
117
118 /*
119 * Simulate mode select g0 with mode select g1.
120 */
121 EXPORT int
mode_select_sg0(scgp,dp,cnt,smp,pf)122 mode_select_sg0(scgp, dp, cnt, smp, pf)
123 SCSI *scgp;
124 Uchar *dp;
125 int cnt;
126 int smp;
127 int pf;
128 {
129 Uchar xmode[256+4];
130 int amt = cnt;
131
132 if (amt < 1 || amt > 255) {
133 /* XXX clear SCSI error codes ??? */
134 return (-1);
135 }
136
137 if (amt < 4) { /* Data length. medium type & VU */
138 amt += 1;
139 } else {
140 amt += 4;
141 movebytes(&dp[4], &xmode[8], cnt-4);
142 }
143 xmode[0] = 0;
144 xmode[1] = 0;
145 xmode[2] = dp[1];
146 xmode[3] = dp[2];
147 xmode[4] = 0;
148 xmode[5] = 0;
149 i_to_2_byte(&xmode[6], (unsigned int)dp[3]);
150
151 if (scgp->verbose) scg_prbytes("Mode Parameters (un-converted)", dp, cnt);
152
153 return (mode_select_g1(scgp, xmode, amt, smp, pf));
154 }
155
156 /*
157 * Simulate mode sense g0 with mode sense g1.
158 */
159 EXPORT int
mode_sense_sg0(scgp,dp,cnt,page,pcf)160 mode_sense_sg0(scgp, dp, cnt, page, pcf)
161 SCSI *scgp;
162 Uchar *dp;
163 int cnt;
164 int page;
165 int pcf;
166 {
167 Uchar xmode[256+4];
168 int amt = cnt;
169 int len;
170
171 if (amt < 1 || amt > 255) {
172 /* XXX clear SCSI error codes ??? */
173 return (-1);
174 }
175
176 fillbytes((caddr_t)xmode, sizeof (xmode), '\0');
177 if (amt < 4) { /* Data length. medium type & VU */
178 amt += 1;
179 } else {
180 amt += 4;
181 }
182 if (mode_sense_g1(scgp, xmode, amt, page, pcf) < 0)
183 return (-1);
184
185 amt = cnt - scg_getresid(scgp);
186 /*
187 * For tests: Solaris 8 & LG CD-ROM always returns resid == amt
188 */
189 /* amt = cnt;*/
190 if (amt > 4)
191 movebytes(&xmode[8], &dp[4], amt-4);
192 len = a_to_u_2_byte(xmode);
193 if (len == 0) {
194 dp[0] = 0;
195 } else if (len < 6) {
196 if (len > 2)
197 len = 2;
198 dp[0] = len;
199 } else {
200 dp[0] = len - 3;
201 }
202 dp[1] = xmode[2];
203 dp[2] = xmode[3];
204 len = a_to_u_2_byte(&xmode[6]);
205 dp[3] = len;
206
207 if (scgp->verbose) scg_prbytes("Mode Sense Data (converted)", dp, amt);
208 return (0);
209 }
210
211 EXPORT int
mode_select_g0(scgp,dp,cnt,smp,pf)212 mode_select_g0(scgp, dp, cnt, smp, pf)
213 SCSI *scgp;
214 Uchar *dp;
215 int cnt;
216 int smp;
217 int pf;
218 {
219 register struct scg_cmd *scmd = scgp->scmd;
220
221 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
222 scmd->addr = (caddr_t)dp;
223 scmd->size = cnt;
224 scmd->flags = SCG_DISRE_ENA;
225 scmd->cdb_len = SC_G0_CDBLEN;
226 scmd->sense_len = CCS_SENSE_LEN;
227 scmd->cdb.g0_cdb.cmd = SC_MODE_SELECT;
228 scmd->cdb.g0_cdb.lun = scg_lun(scgp);
229 scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
230 scmd->cdb.g0_cdb.count = cnt;
231
232 if (scgp->verbose) {
233 error("%s ", smp?"Save":"Set ");
234 scg_prbytes("Mode Parameters", dp, cnt);
235 }
236
237 scgp->cmdname = "mode select g0";
238
239 return (scg_cmd(scgp));
240 }
241
242 EXPORT int
mode_select_g1(scgp,dp,cnt,smp,pf)243 mode_select_g1(scgp, dp, cnt, smp, pf)
244 SCSI *scgp;
245 Uchar *dp;
246 int cnt;
247 int smp;
248 int pf;
249 {
250 register struct scg_cmd *scmd = scgp->scmd;
251
252 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
253 scmd->addr = (caddr_t)dp;
254 scmd->size = cnt;
255 scmd->flags = SCG_DISRE_ENA;
256 scmd->cdb_len = SC_G1_CDBLEN;
257 scmd->sense_len = CCS_SENSE_LEN;
258 scmd->cdb.g1_cdb.cmd = 0x55;
259 scmd->cdb.g1_cdb.lun = scg_lun(scgp);
260 scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
261 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
262
263 if (scgp->verbose) {
264 printf("%s ", smp?"Save":"Set ");
265 scg_prbytes("Mode Parameters", dp, cnt);
266 }
267
268 scgp->cmdname = "mode select g1";
269
270 return (scg_cmd(scgp));
271 }
272
273 EXPORT int
mode_sense_g0(scgp,dp,cnt,page,pcf)274 mode_sense_g0(scgp, dp, cnt, page, pcf)
275 SCSI *scgp;
276 Uchar *dp;
277 int cnt;
278 int page;
279 int pcf;
280 {
281 register struct scg_cmd *scmd = scgp->scmd;
282
283 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
284 scmd->addr = (caddr_t)dp;
285 scmd->size = 0xFF;
286 scmd->size = cnt;
287 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
288 scmd->cdb_len = SC_G0_CDBLEN;
289 scmd->sense_len = CCS_SENSE_LEN;
290 scmd->cdb.g0_cdb.cmd = SC_MODE_SENSE;
291 scmd->cdb.g0_cdb.lun = scg_lun(scgp);
292 #ifdef nonono
293 scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
294 #endif
295 scmd->cdb.g0_cdb.mid_addr = (page&0x3F) | ((pcf<<6)&0xC0);
296 scmd->cdb.g0_cdb.count = page ? 0xFF : 24;
297 scmd->cdb.g0_cdb.count = cnt;
298
299 scgp->cmdname = "mode sense g0";
300
301 if (scg_cmd(scgp) < 0)
302 return (-1);
303 if (scgp->verbose) scg_prbytes("Mode Sense Data", dp, cnt - scg_getresid(scgp));
304 return (0);
305 }
306
307 EXPORT int
mode_sense_g1(scgp,dp,cnt,page,pcf)308 mode_sense_g1(scgp, dp, cnt, page, pcf)
309 SCSI *scgp;
310 Uchar *dp;
311 int cnt;
312 int page;
313 int pcf;
314 {
315 register struct scg_cmd *scmd = scgp->scmd;
316
317 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
318 scmd->addr = (caddr_t)dp;
319 scmd->size = cnt;
320 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
321 scmd->cdb_len = SC_G1_CDBLEN;
322 scmd->sense_len = CCS_SENSE_LEN;
323 scmd->cdb.g1_cdb.cmd = 0x5A;
324 scmd->cdb.g1_cdb.lun = scg_lun(scgp);
325 #ifdef nonono
326 scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
327 #endif
328 scmd->cdb.g1_cdb.addr[0] = (page&0x3F) | ((pcf<<6)&0xC0);
329 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
330
331 scgp->cmdname = "mode sense g1";
332
333 if (scg_cmd(scgp) < 0)
334 return (-1);
335 if (scgp->verbose) scg_prbytes("Mode Sense Data", dp, cnt - scg_getresid(scgp));
336 return (0);
337 }
338