"Fossies" - the Fresh Open Source Software Archive

Member "hdparm-9.60/apt.c" (21 Nov 2020, 8026 Bytes) of package /linux/misc/hdparm-9.60.tar.gz:


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 "apt.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.58_vs_9.60.

    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <fcntl.h>
    4 #include <string.h>
    5 #include <unistd.h>
    6 #include <sys/ioctl.h>
    7 #include <linux/cdrom.h>
    8 #include <scsi/scsi.h>
    9 #include <scsi/sg.h>
   10 #include <sys/types.h>
   11 #include <errno.h>
   12 #include "hdparm.h"
   13 #include "sgio.h"
   14 
   15 /*
   16  * apt - Support for ATA PASS THROUGH devices. Currently supported only
   17  *       JMicron devices.
   18  *
   19  * Copyright (c) 2009   Jan Friesse <jfriesse@gmail.com>
   20  *
   21  * Magic numbers are taken from smartmontools source code
   22  * (http://smartmontools.sourceforge.net/)
   23  *
   24  * You may use/distribute this freely, under the terms of either
   25  * (your choice) the GNU General Public License version 2,
   26  * or a BSD style license.
   27  */
   28 
   29 #ifdef SG_IO
   30 
   31 /* Device initialization functions */
   32 static int apt_jmicron_int_init(int fd);
   33 
   34 /* Device sg16 functions*/
   35 static int apt_jmicron_sg16(int fd, int rw, int dma, struct ata_tf *tf,
   36         void *data, unsigned int data_bytes, unsigned int timeout_secs);
   37 
   38 /* Structs */
   39 struct apt_usb_id_entry {
   40     int vendor_id;
   41     int product_id;
   42     int version;
   43     const char *type;
   44     int (*init_func)(int fd);
   45     int (*sg16_func)(int fd, int rw, int dma, struct ata_tf *tf,
   46         void *data, unsigned int data_bytes, unsigned int timeout_secs);
   47 
   48 };
   49 
   50 struct apt_data_struct {
   51     int is_apt;
   52     struct apt_usb_id_entry id;
   53     int verbose;
   54     union {
   55         struct {
   56             int port;
   57         } jmicron;
   58     };
   59 };
   60 
   61 static struct apt_data_struct apt_data;
   62 
   63 const char apt_ds_jmicron[] = "jmicron";
   64 const char apt_ds_unsup[]   = "unsupported";
   65 
   66 const struct apt_usb_id_entry apt_usb_id_map[] = {
   67     {0x152d, 0x2329, 0x0100, apt_ds_jmicron,
   68         apt_jmicron_int_init, apt_jmicron_sg16}, /* JMicron JM20329 (USB->SATA) */
   69     {0x152d, 0x2336, 0x0100, apt_ds_jmicron,
   70         apt_jmicron_int_init, apt_jmicron_sg16}, /* JMicron JM20336 (USB+SATA->SATA, USB->2xSATA) */
   71     {0x152d, 0x2338, 0x0100, apt_ds_jmicron,
   72         apt_jmicron_int_init, apt_jmicron_sg16}, /* JMicron JM20337/8 (USB->SATA+PATA, USB+SATA->PATA) */
   73     {0x152d, 0x2339, 0x0100, apt_ds_jmicron,
   74         apt_jmicron_int_init, apt_jmicron_sg16}, /* JMicron JM20339 (USB->SATA) */
   75     {0x0c0b, 0xb157, 0x0100, apt_ds_jmicron,
   76         apt_jmicron_int_init, apt_jmicron_sg16}  /* ioSafe Solo */
   77 };
   78 
   79 int apt_detect (int fd, int verbose)
   80 {
   81     int err;
   82     unsigned int i;
   83 
   84     apt_data.is_apt = 0;
   85 
   86     err = sysfs_get_attr_recursive(fd, "idVendor", "%x", &apt_data.id.vendor_id, NULL, verbose);
   87     if (err) {
   88         if (verbose) printf("APT: No idVendor found -> not USB bridge device\n");
   89         return 0;
   90     }
   91 
   92     err = sysfs_get_attr_recursive(fd, "idProduct", "%x", &apt_data.id.product_id, NULL, verbose);
   93     if (err) return 0;
   94 
   95     err = sysfs_get_attr_recursive(fd, "bcdDevice", "%x", &apt_data.id.version, NULL, verbose);
   96     if (err) return 0;
   97 
   98     if (verbose)
   99         printf("APT: USB ID = 0x%04x:0x%04x (0x%03x)\n", apt_data.id.vendor_id, apt_data.id.product_id,
  100           apt_data.id.version);
  101 
  102     /* We have all needed informations, let's find if we support that device*/
  103     for (i = 0; i < sizeof(apt_usb_id_map)/sizeof(*apt_usb_id_map); i++) {
  104         if (apt_data.id.vendor_id == apt_usb_id_map[i].vendor_id &&
  105             apt_data.id.product_id == apt_usb_id_map[i].product_id) {
  106             /* Maybe two devices with same vendor and product id -> use version*/
  107             if (apt_usb_id_map[i].version > 0 && apt_data.id.type &&
  108                 apt_usb_id_map[i].version == apt_data.id.version) {
  109                 apt_data.id.type = apt_usb_id_map[i].type;
  110                 apt_data.id.init_func = apt_usb_id_map[i].init_func;
  111                 apt_data.id.sg16_func = apt_usb_id_map[i].sg16_func;
  112             }
  113 
  114             /* We don't have type -> set it (don't care about version) */
  115             if (!apt_data.id.type) {
  116                 apt_data.id.type = apt_usb_id_map[i].type;
  117                 apt_data.id.init_func = apt_usb_id_map[i].init_func;
  118                 apt_data.id.sg16_func = apt_usb_id_map[i].sg16_func;
  119             }
  120         }
  121     }
  122 
  123     if (!apt_data.id.type || apt_data.id.type == apt_ds_unsup) {
  124         if (verbose)
  125             printf("APT: Unsupported device\n");
  126 
  127         return 0;
  128     }
  129 
  130     apt_data.is_apt = 1;
  131     if (verbose)
  132         printf("APT: Found supported device %s\n", apt_data.id.type);
  133 
  134     apt_data.verbose = verbose;
  135 
  136     return (apt_data.id.init_func(fd));
  137 }
  138 
  139 int apt_is_apt (void)
  140 {
  141     return apt_data.is_apt;
  142 }
  143 
  144 int apt_sg16(int fd, int rw, int dma, struct ata_tf *tf,
  145         void *data, unsigned int data_bytes, unsigned int timeout_secs)
  146 {
  147     return apt_data.id.sg16_func(fd, rw, dma, tf, data, data_bytes, timeout_secs);
  148 }
  149 
  150 static void dump_bytes (const char *prefix, unsigned char *p, int len)
  151 {
  152     int i;
  153 
  154     if (prefix)
  155         fprintf(stderr, "%s: ", prefix);
  156     for (i = 0; i < len; ++i)
  157         fprintf(stderr, " %02x", p[i]);
  158     fprintf(stderr, "\n");
  159 }
  160 
  161 /***** JMicron support ********/
  162 static int apt_jmicron_int_sg(int fd, int rw, int dma, struct ata_tf *tf,
  163         void *data, unsigned int data_bytes, unsigned int timeout_secs,
  164         int port)
  165 {
  166     unsigned char cdb[12];
  167     struct scsi_sg_io_hdr io_hdr;
  168 
  169     if (dma && apt_data.verbose)
  170         printf("APT: JMicron doesn't support DMA\n");
  171 
  172     if (tf->is_lba48) {
  173         if (apt_data.verbose)
  174             fprintf(stderr, "APT: JMicron doesn't support 48-bit ATA commands\n");
  175                 errno = EBADE;
  176                 return -1;
  177     }
  178 
  179     memset(&cdb, 0, sizeof(cdb));
  180     memset(&io_hdr, 0, sizeof(struct scsi_sg_io_hdr));
  181 
  182     // Build pass through command
  183     cdb[ 0] = 0xdf;
  184     cdb[ 1] = (rw ? 0x00 : 0x10);
  185     cdb[ 2] = 0x00;
  186     cdb[ 3] = (unsigned char)((data ? data_bytes : 0) >> 8);
  187     cdb[ 4] = (unsigned char)((data ? data_bytes : 0) );
  188     cdb[ 5] = tf->lob.feat;
  189     cdb[ 6] = tf->lob.nsect;
  190     cdb[ 7] = tf->lob.lbal;
  191     cdb[ 8] = tf->lob.lbam;
  192     cdb[ 9] = tf->lob.lbah;
  193     cdb[10] = (port ? port : apt_data.jmicron.port);
  194     cdb[11] =  tf->command;
  195 
  196     io_hdr.interface_id = 'S';
  197     io_hdr.mx_sb_len    = 0;
  198     io_hdr.dxfer_direction  = data ? (rw ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV) : SG_DXFER_NONE;
  199     io_hdr.dxfer_len    = data ? data_bytes : 0;
  200     io_hdr.dxferp       = data;
  201     io_hdr.cmdp     = cdb;
  202     io_hdr.pack_id      = tf_to_lba(tf);
  203     io_hdr.timeout      = (timeout_secs ? timeout_secs : 5) * 1000; /* msecs */
  204     io_hdr.cmd_len      = sizeof(cdb);
  205 
  206     if (apt_data.verbose)
  207         dump_bytes("outgoing cdb", cdb, sizeof(cdb));
  208     if (ioctl(fd, SG_IO, &io_hdr) == -1) {
  209         if (apt_data.verbose)
  210             perror("ioctl(fd,SG_IO)");
  211         return -1;      /* SG_IO not supported */
  212         }
  213     if (apt_data.verbose)
  214         fprintf(stderr, "SG_IO: ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x\n",
  215             io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status);
  216 
  217     if (io_hdr.host_status || io_hdr.driver_status) {
  218         errno = EBADE;
  219         return -1;
  220     }
  221 
  222     return 0;
  223 }
  224 
  225 static int apt_jmicron_int_get_registers(int fd, unsigned short addr,
  226                     unsigned char * buf, unsigned short size)
  227 {
  228     struct ata_tf tf;
  229 
  230     memset(&tf, 0, sizeof(tf));
  231 
  232     tf.lob.feat = 0x00;
  233     tf.lob.nsect    = (unsigned char)(addr >> 8);
  234     tf.lob.lbal = (unsigned char)(addr);
  235     tf.lob.lbam = 0x00;
  236     tf.lob.lbah = 0x00;
  237     tf.command  = 0xfd;
  238 
  239     return apt_jmicron_int_sg(fd, 0, 0, &tf, buf, (unsigned int)size, 0, 0x00);
  240 }
  241 
  242 static int apt_jmicron_int_init(int fd)
  243 {
  244     unsigned char regbuf = 0;
  245     int res;
  246 
  247     if ((res = apt_jmicron_int_get_registers(fd, 0x720F, &regbuf, 1)) == -1) {
  248         return res;
  249     }
  250 
  251     if (regbuf & 0x04) {
  252         apt_data.jmicron.port = 0xa0;
  253     } else if (regbuf & 0x40) {
  254         apt_data.jmicron.port = 0xb0;
  255     } else {
  256         perror("APT: No JMicron device connected");
  257         errno = ENODEV;
  258         return -1;
  259     }
  260 
  261     if (apt_data.verbose)
  262         printf("APT: JMicron Port: 0x%X\n", apt_data.jmicron.port);
  263     return 0;
  264 }
  265 
  266 static int apt_jmicron_sg16(int fd, int rw, int dma, struct ata_tf *tf,
  267         void *data, unsigned int data_bytes, unsigned int timeout_secs)
  268 {
  269 
  270     return apt_jmicron_int_sg(fd, rw, dma, tf, data, data_bytes, timeout_secs, 0);
  271 }
  272 
  273 #else
  274 /* No SGIO -> no support*/
  275 int apt_detect (int fd, int verbose)
  276 {
  277     if (verbose)
  278         printf("APT: SGIO Support needed for fd %d\n", fd);
  279     return 0;
  280 }
  281 
  282 int apt_is_apt (void)
  283 {
  284     return 0;
  285 }
  286 
  287 int apt_sg16(int fd, int rw, int dma, struct ata_tf *tf,
  288         void *data, unsigned int data_bytes, unsigned int timeout_secs)
  289 {
  290     printf("APT: SG16 fd %d rw %d dma %d tf %p data %p data_bytes %d timeout %d need SGIO\n",
  291         fd, rw, dma, tf, data, data_bytes, timeout_secs);
  292     return -1;
  293 }
  294 #endif