"Fossies" - the Fresh Open Source Software Archive 
Member "sdparm-1.12/src/sdparm_access.c" (22 Mar 2021, 15488 Bytes) of package /linux/misc/sdparm-1.12.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "sdparm_access.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.11_vs_1.12.
1 /*
2 * Copyright (c) 2005-2021, Douglas Gilbert
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdbool.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #define __STDC_FORMAT_MACROS 1
35 #include <inttypes.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include "sdparm.h"
42 #include "sg_lib.h"
43 #include "sg_unaligned.h"
44 #include "sg_pr2serr.h"
45
46 /* sdparm_access.c : helpers for sdparm to access tables in
47 * sdparm_data.c
48 */
49
50 /* Returns true if left argument is "equal" to the right argument. l_pdt_s
51 * is a compound PDT (SCSI Peripheral Device Type) or a negative number
52 * which represents a wildcard (i.e. match anything). r_pdt_s has a similar
53 * form. PDT values are 5 bits long (0 to 31) and a compound pdt_s is
54 * formed by shifting the second (upper) PDT by eight bits to the left and
55 * OR-ing it with the first PDT. The pdt_s values must be defined so
56 * PDT_DISK (0) is _not_ the upper value in a compound pdt_s. */
57 bool
58 pdt_s_eq(int l_pdt_s, int r_pdt_s)
59 {
60 bool upper_l = !!(l_pdt_s & PDT_UPPER_MASK);
61 bool upper_r = !!(r_pdt_s & PDT_UPPER_MASK);
62
63 if ((l_pdt_s < 0) || (r_pdt_s < 0))
64 return true;
65 if (!upper_l && !upper_r)
66 return l_pdt_s == r_pdt_s;
67 else if (upper_l && upper_r)
68 return (((PDT_UPPER_MASK & l_pdt_s) == (PDT_UPPER_MASK & r_pdt_s)) ||
69 ((PDT_LOWER_MASK & l_pdt_s) == (PDT_LOWER_MASK & r_pdt_s)));
70 else if (upper_l)
71 return (((PDT_LOWER_MASK & l_pdt_s) == r_pdt_s) ||
72 ((PDT_UPPER_MASK & l_pdt_s) >> 8) == r_pdt_s);
73 return (((PDT_LOWER_MASK & r_pdt_s) == l_pdt_s) ||
74 ((PDT_UPPER_MASK & r_pdt_s) >> 8) == l_pdt_s);
75 }
76
77 /* Returns 1 if strings equal (same length, characters same or only differ
78 * by case), else returns 0. Assumes 7 bit ASCII (English alphabet). */
79 int
80 sdp_strcase_eq(const char * s1p, const char * s2p)
81 {
82 int c1, c2;
83
84 do {
85 c1 = *s1p++;
86 c2 = *s2p++;
87 if (c1 != c2) {
88 if (c2 >= 'a')
89 c2 = toupper(c2);
90 else if (c1 >= 'a')
91 c1 = toupper(c1);
92 else
93 return 0;
94 if (c1 != c2)
95 return 0;
96 }
97 } while (c1);
98 return 1;
99 }
100
101 /* Returns 1 if strings equal up to the nth character (characters same or only
102 * differ by case), else returns 0. Assumes 7 bit ASCII (English alphabet). */
103 int
104 sdp_strcase_eq_upto(const char * s1p, const char * s2p, int n)
105 {
106 int k, c1, c2;
107
108 for (k = 0; k < n; ++k) {
109 c1 = *s1p++;
110 c2 = *s2p++;
111 if (c1 != c2) {
112 if (c2 >= 'a')
113 c2 = toupper(c2);
114 else if (c1 >= 'a')
115 c1 = toupper(c1);
116 else
117 return 0;
118 if (c1 != c2)
119 return 0;
120 }
121 if (0 == c1)
122 break;
123 }
124 return 1;
125 }
126
127
128 /* Returns length of mode page. Assumes mp pointing at start of a mode
129 * page (not the start of a MODE SENSE response). */
130 int
131 sdp_mpage_len(const uint8_t * mp)
132 {
133 /* if SPF (byte 0, bit 6) is set then 4 byte header, else 2 byte header */
134 return (mp[0] & 0x40) ? (sg_get_unaligned_be16(mp + 2) + 4) : (mp[1] + 2);
135 }
136
137 const struct sdparm_mode_page_t *
138 sdp_get_mpage_t(int page_num, int subpage_num, int pdt, int transp_proto,
139 int vendor_id)
140 {
141 const struct sdparm_mode_page_t * mpp;
142
143 if (vendor_id >= 0) {
144 const struct sdparm_vendor_pair * vpp;
145
146 vpp = sdp_get_vendor_pair(vendor_id);
147 mpp = (vpp ? vpp->mpage : NULL);
148 } else if ((transp_proto >= 0) && (transp_proto < 16))
149 mpp = sdparm_transport_mp[transp_proto].mpage;
150 else
151 mpp = sdparm_gen_mode_pg;
152 if (NULL == mpp)
153 return NULL;
154
155 for ( ; mpp->acron; ++mpp) {
156 if ((page_num == mpp->page) && (subpage_num == mpp->subpage)) {
157 if ((pdt < 0) || (mpp->pdt_s < 0) || pdt_s_eq(mpp->pdt_s, pdt))
158 return mpp;
159 }
160 }
161 return NULL;
162 }
163
164 const struct sdparm_mode_page_t *
165 sdp_get_mpt_with_str(int page_num, int subpage_num, int pdt, int transp_proto,
166 int vendor_id, bool plus_acron, bool hex, int b_len,
167 char * bp)
168 {
169 int len = b_len - 1;
170 const struct sdparm_mode_page_t * mpp = NULL;
171 const char * cp;
172
173 if (len < 0)
174 return mpp;
175 bp[len] = '\0';
176 /* first try to match given pdt */
177 mpp = sdp_get_mpage_t(page_num, subpage_num, pdt, transp_proto,
178 vendor_id);
179 if (NULL == mpp) /* didn't match specific pdt so try -1 (ie. SPC) */
180 mpp = sdp_get_mpage_t(page_num, subpage_num, -1, transp_proto,
181 vendor_id);
182 if (mpp && mpp->name) {
183 cp = mpp->acron;
184 if (NULL == cp)
185 cp = "";
186 if (hex) {
187 if (0 == subpage_num) {
188 if (plus_acron)
189 snprintf(bp, len, "%s [%s: 0x%x]", mpp->name, cp,
190 page_num);
191 else
192 snprintf(bp, len, "%s [0x%x]", mpp->name, page_num);
193 } else {
194 if (plus_acron)
195 snprintf(bp, len, "%s [%s: 0x%x,0x%x]", mpp->name, cp,
196 page_num, subpage_num);
197 else
198 snprintf(bp, len, "%s [0x%x,0x%x]", mpp->name, page_num,
199 subpage_num);
200 }
201 } else {
202 if (plus_acron)
203 snprintf(bp, len, "%s [%s]", mpp->name, cp);
204 else
205 snprintf(bp, len, "%s", mpp->name);
206 }
207 } else {
208 if (0 == subpage_num)
209 snprintf(bp, len, "[0x%x]", page_num);
210 else
211 snprintf(bp, len, "[0x%x,0x%x]", page_num, subpage_num);
212 }
213 return mpp;
214 }
215
216 const struct sdparm_mode_page_t *
217 sdp_find_mpt_by_acron(const char * ap, int transp_proto, int vendor_id)
218 {
219 const struct sdparm_mode_page_t * mpp;
220
221 if (vendor_id >= 0) {
222 const struct sdparm_vendor_pair * vpp;
223
224 vpp = sdp_get_vendor_pair(vendor_id);
225 mpp = (vpp ? vpp->mpage : NULL);
226 } else if ((transp_proto >= 0) && (transp_proto < 16))
227 mpp = sdparm_transport_mp[transp_proto].mpage;
228 else
229 mpp = sdparm_gen_mode_pg;
230 if (NULL == mpp)
231 return NULL;
232
233 for ( ; mpp->acron; ++mpp) {
234 if (sdp_strcase_eq(mpp->acron, ap))
235 return mpp;
236 }
237 return NULL;
238 }
239
240 const struct sdparm_vpd_page_t *
241 sdp_get_vpd_detail(int page_num, int subvalue, int pdt)
242 {
243 const struct sdparm_vpd_page_t * vpp;
244 int sv, ty;
245
246 sv = (subvalue < 0) ? 1 : 0;
247 ty = (pdt < 0) ? 1 : 0;
248 for (vpp = sdparm_vpd_pg; vpp->acron; ++vpp) {
249 if ((page_num == vpp->vpd_num) &&
250 (sv || (subvalue == vpp->subvalue)) &&
251 (ty || (pdt == vpp->pdt_s)))
252 return vpp;
253 }
254 if (! ty)
255 return sdp_get_vpd_detail(page_num, subvalue, -1);
256 if (! sv)
257 return sdp_get_vpd_detail(page_num, -1, -1);
258 return NULL;
259 }
260
261 const struct sdparm_vpd_page_t *
262 sdp_find_vpd_by_acron(const char * ap)
263 {
264 const struct sdparm_vpd_page_t * vpp;
265
266 for (vpp = sdparm_vpd_pg; vpp->acron; ++vpp) {
267 if (sdp_strcase_eq(vpp->acron, ap))
268 return vpp;
269 }
270 return NULL;
271 }
272
273 char *
274 sdp_get_transport_name(int proto_num, int b_len, char * b)
275 {
276 char d[128];
277
278 if (NULL == b)
279 ;
280 else if (b_len < 2) {
281 if (1 == b_len)
282 b[0] = '\0';
283 } else
284 snprintf(b, b_len, "%s", sg_get_trans_proto_str(proto_num, sizeof(d),
285 d));
286 return b;
287 }
288
289 int
290 sdp_find_transport_id_by_acron(const char * ap)
291 {
292 const struct sdparm_val_desc_t * t_vdp;
293 const struct sdparm_val_desc_t * t_addp;
294
295 for (t_vdp = sdparm_transport_id; t_vdp->desc; ++t_vdp) {
296 if (sdp_strcase_eq(t_vdp->desc, ap))
297 return t_vdp->val;
298 }
299 /* No match ... try additional transport acronyms */
300 for (t_addp = sdparm_add_transport_acron; t_addp->desc; ++t_addp) {
301 if (sdp_strcase_eq(t_addp->desc, ap))
302 return t_addp->val;
303 }
304 return -1;
305 }
306
307 const char *
308 sdp_get_vendor_name(int vendor_id)
309 {
310 const struct sdparm_vendor_name_t * vnp;
311
312 for (vnp = sdparm_vendor_id; vnp->acron; ++vnp) {
313 if (vendor_id == vnp->vendor_id)
314 return vnp->name;
315 }
316 return NULL;
317 }
318
319 const struct sdparm_vendor_name_t *
320 sdp_find_vendor_by_acron(const char * ap)
321 {
322 const struct sdparm_vendor_name_t * vnp;
323
324 for (vnp = sdparm_vendor_id; vnp->acron; ++vnp) {
325 if (sdp_strcase_eq_upto(vnp->acron, ap, strlen(vnp->acron)))
326 return vnp;
327 }
328 return NULL;
329 }
330
331 const struct sdparm_vendor_pair *
332 sdp_get_vendor_pair(int vendor_id)
333 {
334 return ((vendor_id >= 0) && (vendor_id < sdparm_vendor_mp_len))
335 ? (sdparm_vendor_mp + vendor_id) : NULL;
336 }
337
338 /* Searches mpage items table from (and including) the current position
339 * looking for the first match on 'ap' (pointer to acromym). Checks
340 * against the inbuilt table (in sdparm_data.c) of generic (when both
341 * transp_proto and vendor_id are -1), transport (when transp_proto is
342 * >= 0) or vendor (when vendor_id is >= 0) mode page items (fields).
343 * If found a pointer to that mitem is returned and *from_p is set to
344 * the offset after the match. If not found then NULL is returned and
345 * *from_p is set to the offset of the sentinel at the end of the
346 * selected mitem array. Start iteration by setting from_p to NULL or
347 * point it at -1. */
348 const struct sdparm_mode_page_item *
349 sdp_find_mitem_by_acron(const char * ap, int * from_p, int transp_proto,
350 int vendor_id)
351 {
352 int k = 0;
353 const struct sdparm_mode_page_item * mpi;
354
355 if (from_p) {
356 k = *from_p;
357 if (k < 0)
358 k = 0;
359 }
360 if (vendor_id >= 0) {
361 const struct sdparm_vendor_pair * vpp;
362
363 vpp = sdp_get_vendor_pair(vendor_id);
364 mpi = (vpp ? vpp->mitem : NULL);
365 } else if ((transp_proto >= 0) && (transp_proto < 16))
366 mpi = sdparm_transport_mp[transp_proto].mitem;
367 else
368 mpi = sdparm_mitem_arr;
369 if (NULL == mpi)
370 return NULL;
371
372 for (mpi += k; mpi->acron; ++k, ++mpi) {
373 if (sdp_strcase_eq(mpi->acron, ap))
374 break;
375 }
376 if (NULL == mpi->acron)
377 mpi = NULL;
378 if (from_p)
379 *from_p = (mpi ? (k + 1) : k);
380 return mpi;
381 }
382
383 uint64_t
384 sdp_mitem_get_value(const struct sdparm_mode_page_item *mpi,
385 const uint8_t * mp)
386 {
387 return sg_get_big_endian(mp + mpi->start_byte, mpi->start_bit,
388 mpi->num_bits);
389 }
390
391 /* Gets a mode page item's value given a pointer to the mode page response
392 * (mp). If all_setp is non-NULL then checks 8, 16, 24, 32, 48 and 64 bit
393 * quantities for all bits set (e.g. for 8 bits that would be 0xff) and if
394 * so sets the bool addressed by all_setp to true. Otherwise if all_setp
395 * is non-NULL then it sets the bool addressed by all_setp to false.
396 * Returns the value in an unsigned 64 bit integer. To print a value as a
397 * signed quantity use sdp_print_signed_decimal(). */
398 uint64_t
399 sdp_mitem_get_value_check(const struct sdparm_mode_page_item *mpi,
400 const uint8_t * mp, bool * all_setp)
401 {
402 uint64_t res;
403
404 res = sg_get_big_endian(mp + mpi->start_byte, mpi->start_bit,
405 mpi->num_bits);
406 if (all_setp) {
407 switch (mpi->num_bits) {
408 case 8:
409 if (0xff == res)
410 *all_setp = true;
411 break;
412 case 16:
413 if (0xffff == res)
414 *all_setp = true;
415 break;
416 case 24:
417 if (0xffffff == res)
418 *all_setp = true;
419 break;
420 case 32:
421 if (0xffffffff == res)
422 *all_setp = true;
423 break;
424 case 48:
425 if (0xffffffffffffULL == res)
426 *all_setp = true;
427 break;
428 case 64:
429 if (0xffffffffffffffffULL == res)
430 *all_setp = true;
431 break;
432 default:
433 *all_setp = false;
434 break;
435 }
436 }
437 return res;
438 }
439
440 void
441 sdp_print_signed_decimal(uint64_t u, int num_bits, bool leading_zeros)
442 {
443 unsigned int ui;
444 uint8_t uc;
445
446 switch (num_bits) {
447 /* could support other num_bits, as required */
448 case 4: /* -8 to 7 */
449 uc = u & 0xf;
450 if (0x8 & uc)
451 uc |= 0xf0; /* sign extend */
452 if (leading_zeros)
453 printf("%02hhd", (signed char)uc);
454 else
455 printf("%hhd", (signed char)uc);
456 break;
457 case 8: /* -128 to 127 */
458 if (leading_zeros)
459 printf("%02hhd", (signed char)u);
460 else
461 printf("%hhd", (signed char)u);
462 break;
463 case 16: /* -32768 to 32767 */
464 if (leading_zeros)
465 printf("%02hd", (short int)u);
466 else
467 printf("%hd", (short int)u);
468 break;
469 case 24:
470 ui = 0xffffff & u;
471 if (0x800000 & ui)
472 ui |= 0xff000000;
473 if (leading_zeros)
474 printf("%02d", (int)ui);
475 else
476 printf("%d", (int)ui);
477 break;
478 case 32:
479 if (leading_zeros)
480 printf("%02d", (int)u);
481 else
482 printf("%d", (int)u);
483 break;
484 case 64:
485 default:
486 if (leading_zeros)
487 printf("%02" PRId64 , (int64_t)u);
488 else
489 printf("%" PRId64 , (int64_t)u);
490 break;
491 }
492 }
493
494 /* Place 'val' at an offset to 'mp' as indicated by mpi. */
495 void
496 sdp_mitem_set_value(uint64_t val, const struct sdparm_mode_page_item * mpi,
497 uint8_t * mp)
498 {
499 sg_set_big_endian(val, mp + mpi->start_byte, mpi->start_bit,
500 mpi->num_bits);
501 }
502
503 char *
504 sdp_get_ansi_version_str(int version, int buff_len, char * buff)
505 {
506 version &= 0x7;
507 buff[buff_len - 1] = '\0';
508 strncpy(buff, sdparm_ansi_version_arr[version], buff_len - 1);
509 return buff;
510 }
511
512 int
513 sdp_get_desc_id(int flags)
514 {
515 return (MF_DESC_ID_MASK & flags) >> MF_DESC_ID_SHIFT;
516 }