lib/sg_cmds_extra.c
int
sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
             int timeout_secs, void * dinp, void * doutp, int dlen,
             unsigned char * sensep, int max_sense_len,
             unsigned char * ata_return_dp, int max_ata_return_len,
             int * residp, int verbose)
{
    int k, res, slen, duration;
    unsigned char aptCmdBlk[ATA_PT_16_CMDLEN] =
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    unsigned char * sp;
    const unsigned char * ucp;
    struct sg_pt_base * ptvp;
    const char * cnamep;
    char b[256];
    int ret = -1;

    b[0] = '\0';
    cnamep = (12 == cdb_len) ?
             "ATA pass through (12)" : "ATA pass through (16)";
    if ((NULL == cdbp) || ((12 != cdb_len) && (16 != cdb_len))) {
        if (verbose) {
            if (NULL == cdbp)
                pr2ws("%s NULL cdb pointer\n", cnamep);
            else
                pr2ws("cdb_len must be 12 or 16\n");
        }
        return -1;
    }
    aptCmdBlk[0] = (12 == cdb_len) ? ATA_PT_12_CMD : ATA_PT_16_CMD;
    if (sensep && (max_sense_len >= (int)sizeof(sense_b))) {
        sp = sensep;
        slen = max_sense_len;
    } else {
        sp = sense_b;
        slen = sizeof(sense_b);
    }
    if (12 == cdb_len)
        memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 11) ? 10 : (cdb_len - 1)));
    else
        memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 15) ? 14 : (cdb_len - 1)));
    if (verbose) {
        pr2ws("    %s cdb: ", cnamep);
        for (k = 0; k < cdb_len; ++k)
            pr2ws("%02x ", aptCmdBlk[k]);
        pr2ws("\n");
    }
    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2ws("%s: out of memory\n", cnamep);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, aptCmdBlk, cdb_len);
    set_scsi_pt_sense(ptvp, sp, slen);
    if (dlen > 0) {
        if (dinp)
            set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen);
        else if (doutp)
            set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen);
    }
    res = do_scsi_pt(ptvp, sg_fd,
                     ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT),
                     verbose);
    if (SCSI_PT_DO_BAD_PARAMS == res) {
        if (verbose)
            pr2ws("%s: bad parameters\n", cnamep);
        goto out;
    } else if (SCSI_PT_DO_TIMEOUT == res) {
        if (verbose)
            pr2ws("%s: timeout\n", cnamep);
        goto out;
    } else if (res > 2) {
        if (verbose)
            pr2ws("%s: do_scsi_pt: errno=%d\n", cnamep, -res);
    }

    if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
        pr2ws("      duration=%d ms\n", duration);

    switch (get_scsi_pt_result_category(ptvp)) {
    case SCSI_PT_RESULT_GOOD:
        if ((sensep) && (max_sense_len > 0))
            *sensep = 0;
        if ((ata_return_dp) && (max_ata_return_len > 0))
            *ata_return_dp = 0;
        if (residp && (dlen > 0))
            *residp = get_scsi_pt_resid(ptvp);
        ret = 0;
        break;
    case SCSI_PT_RESULT_STATUS: /* other than GOOD + CHECK CONDITION */
        if ((sensep) && (max_sense_len > 0))
            *sensep = 0;
        if ((ata_return_dp) && (max_ata_return_len > 0))
            *ata_return_dp = 0;
        ret = get_scsi_pt_status_response(ptvp);
        break;
    case SCSI_PT_RESULT_SENSE:
        if (sensep && (sp != sensep)) {
            k = get_scsi_pt_sense_len(ptvp);
            k = (k > max_sense_len) ? max_sense_len : k;
            memcpy(sensep, sp, k);
        }
        if (ata_return_dp && (max_ata_return_len > 0))  {
            /* search for ATA return descriptor */
            ucp = sg_scsi_sense_desc_find(sp, slen, 0x9);
            if (ucp) {
                k = ucp[1] + 2;
                k = (k > max_ata_return_len) ? max_ata_return_len : k;
                memcpy(ata_return_dp, ucp, k);
            } else
                ata_return_dp[0] = 0x0;
        }
        if (residp && (dlen > 0))
            *residp = get_scsi_pt_resid(ptvp);
        ret = get_scsi_pt_status_response(ptvp);
        break;
    case SCSI_PT_RESULT_TRANSPORT_ERR:
        if (verbose)
            pr2ws("%s: transport error: %s\n", cnamep,
                  get_scsi_pt_transport_err_str(ptvp, sizeof(b), b));
        break;
    case SCSI_PT_RESULT_OS_ERR:
        if (verbose)
            pr2ws("%s: os error: %s\n", cnamep,
                  get_scsi_pt_os_err_str(ptvp, sizeof(b) , b));
        break;
    default:
        if (verbose)
            pr2ws("%s: unknown pt_result_category=%d\n", cnamep,
                  get_scsi_pt_result_category(ptvp));
        break;
    }

out:
    destruct_scsi_pt_obj(ptvp);
    return ret;
}
/* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len
 * is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16
 * then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other
 * value -1 is returned. After copying from cdbp to an internal buffer,
 * the first byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is
 * set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is
 * set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout
 * is set to 60 seconds. For data in or out transfers set dinp or doutp,
 * and dlen to the number of bytes to transfer. If dlen is zero then no data
 * transfer is assumed. If sense buffer obtained then it is written to
 * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained
 * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either
 * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI
 * status value (>= 0) or -1 if other error. Users are expected to check the
 * sense buffer themselves. If available the data in resid is written to
 * residp. Note in SAT-2 and later, fixed format sense data may be placed in
 * *sensep in which case sensep[0]==0x70 .
 */
Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len
is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16
then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other
value -1 is returned. After copying from cdbp to an internal buffer,
the first byte  is set to 0xa1 if cdb_len is 12; or is
set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is
set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout
is set to 60 seconds. For data in or out transfers set dinp or doutp,
and dlen to the number of bytes to transfer. If dlen is zero then no data
transfer is assumed. If sense buffer obtained then it is written to
sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained
then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either
sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI
status value (>= 0) or -1 if other error. Users are expected to check the
sense buffer themselves. If available the data in resid is written to
residp. Note in SAT-2 and later, fixed format sense data may be placed in
*sensep in which case sensep[0]==0x70 .
Invokes a ATA PASS - THROUGH ( 12 or 16 ) SCSI command ( SAT ) . If cdb_len is 12 then a ATA PASS - THROUGH ( 12 ) command is called . If cdb_len is 16 then a ATA PASS - THROUGH ( 16 ) command is called . If cdb_len is any other value - 1 is returned . After copying from cdbp to an internal buffer the first byte is set to 0xa1 if cdb_len is 12 ; or is set to 0x85 if cdb_len is 16 . The last byte ( offset 11 or offset 15 ) is set to 0x0 in the internal buffer . If timeout_secs < = 0 then the timeout is set to 60 seconds . For data in or out transfers set dinp or doutp and dlen to the number of bytes to transfer . If dlen is zero then no data transfer is assumed . If sense buffer obtained then it is written to sensep else sensep [ 0 ] is set to 0x0 . If ATA return descriptor is obtained then written to ata_return_dp else ata_return_dp [ 0 ] is set to 0x0 . Either sensep or ata_return_dp ( or both ) may be NULL pointers . Returns SCSI status value ( > = 0 ) or - 1 if other error . Users are expected to check the sense buffer themselves . If available the data in resid is written to residp . Note in SAT - 2 and later fixed format sense data may be placed in * sensep in which case sensep [ 0 ] == 0x70 .
int
sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
             int timeout_secs, void * dinp, void * doutp, int dlen,
             unsigned char * sensep, int max_sense_len,
             unsigned char * ata_return_dp, int max_ata_return_len,
             int * residp, int verbose)
{
    int k, res, slen, duration;
    unsigned char aptCmdBlk[ATA_PT_16_CMDLEN] =
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    unsigned char * sp;
    const unsigned char * ucp;
    struct sg_pt_base * ptvp;
    const char * cnamep;
    char b[256];
    int ret = -1;
    b[0] = '\0';
    cnamep = (12 == cdb_len) ?
             "ATA pass through (12)" : "ATA pass through (16)";
    if ((NULL == cdbp) || ((12 != cdb_len) && (16 != cdb_len))) {
        if (verbose) {
            if (NULL == cdbp)
                pr2ws("%s NULL cdb pointer\n", cnamep);
            else
                pr2ws("cdb_len must be 12 or 16\n");
        }
        return -1;
    }
    aptCmdBlk[0] = (12 == cdb_len) ? ATA_PT_12_CMD : ATA_PT_16_CMD;
    if (sensep && (max_sense_len >= (int)sizeof(sense_b))) {
        sp = sensep;
        slen = max_sense_len;
    } else {
        sp = sense_b;
        slen = sizeof(sense_b);
    }
    if (12 == cdb_len)
        memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 11) ? 10 : (cdb_len - 1)));
    else
        memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 15) ? 14 : (cdb_len - 1)));
    if (verbose) {
        pr2ws("    %s cdb: ", cnamep);
        for (k = 0; k < cdb_len; ++k)
            pr2ws("%02x ", aptCmdBlk[k]);
        pr2ws("\n");
    }
    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2ws("%s: out of memory\n", cnamep);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, aptCmdBlk, cdb_len);
    set_scsi_pt_sense(ptvp, sp, slen);
    if (dlen > 0) {
        if (dinp)
            set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen);
        else if (doutp)
            set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen);
    }
    res = do_scsi_pt(ptvp, sg_fd,
                     ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT),
                     verbose);
    if (SCSI_PT_DO_BAD_PARAMS == res) {
        if (verbose)
            pr2ws("%s: bad parameters\n", cnamep);
        goto out;
    } else if (SCSI_PT_DO_TIMEOUT == res) {
        if (verbose)
            pr2ws("%s: timeout\n", cnamep);
        goto out;
    } else if (res > 2) {
        if (verbose)
            pr2ws("%s: do_scsi_pt: errno=%d\n", cnamep, -res);
    }
    if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
        pr2ws("      duration=%d ms\n", duration);
    switch (get_scsi_pt_result_category(ptvp)) {
    case SCSI_PT_RESULT_GOOD:
        if ((sensep) && (max_sense_len > 0))
            *sensep = 0;
        if ((ata_return_dp) && (max_ata_return_len > 0))
            *ata_return_dp = 0;
        if (residp && (dlen > 0))
            *residp = get_scsi_pt_resid(ptvp);
        ret = 0;
        break;
    case SCSI_PT_RESULT_STATUS: 
        if ((sensep) && (max_sense_len > 0))
            *sensep = 0;
        if ((ata_return_dp) && (max_ata_return_len > 0))
            *ata_return_dp = 0;
        ret = get_scsi_pt_status_response(ptvp);
        break;
    case SCSI_PT_RESULT_SENSE:
        if (sensep && (sp != sensep)) {
            k = get_scsi_pt_sense_len(ptvp);
            k = (k > max_sense_len) ? max_sense_len : k;
            memcpy(sensep, sp, k);
        }
        if (ata_return_dp && (max_ata_return_len > 0))  {
            ucp = sg_scsi_sense_desc_find(sp, slen, 0x9);
            if (ucp) {
                k = ucp[1] + 2;
                k = (k > max_ata_return_len) ? max_ata_return_len : k;
                memcpy(ata_return_dp, ucp, k);
            } else
                ata_return_dp[0] = 0x0;
        }
        if (residp && (dlen > 0))
            *residp = get_scsi_pt_resid(ptvp);
        ret = get_scsi_pt_status_response(ptvp);
        break;
    case SCSI_PT_RESULT_TRANSPORT_ERR:
        if (verbose)
            pr2ws("%s: transport error: %s\n", cnamep,
                  get_scsi_pt_transport_err_str(ptvp, sizeof(b), b));
        break;
    case SCSI_PT_RESULT_OS_ERR:
        if (verbose)
            pr2ws("%s: os error: %s\n", cnamep,
                  get_scsi_pt_os_err_str(ptvp, sizeof(b) , b));
        break;
    default:
        if (verbose)
            pr2ws("%s: unknown pt_result_category=%d\n", cnamep,
                  get_scsi_pt_result_category(ptvp));
        break;
    }
out:
    destruct_scsi_pt_obj(ptvp);
    return ret;
}
int sg_ll_ata_pt ( int sg_fd , const unsigned char * cdbp , int cdb_len , int timeout_secs , void * dinp , void * doutp , int dlen , unsigned char * sensep , int max_sense_len , unsigned char * ata_return_dp , int max_ata_return_len , int * residp , int verbose ) { int k , res , slen , duration ; unsigned char aptCmdBlk [ ATA_PT_16_CMDLEN ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; unsigned char sense_b [ SENSE_BUFF_LEN ] ; unsigned char * sp ; const unsigned char * ucp ; struct sg_pt_base * ptvp ; const char * cnamep ; char b [ 256 ] ; int ret = -1 ; b [ 0 ] = ' \0 ' ; cnamep = ( 12 == cdb_len ) ? " " : " " ; if ( ( NULL == cdbp ) || ( ( 12 != cdb_len ) && ( 16 != cdb_len ) ) ) { if ( verbose ) { if ( NULL == cdbp ) pr2ws ( " \n " , cnamep ) ; else pr2ws ( " \n " ) ; } return -1 ; } aptCmdBlk [ 0 ] = ( 12 == cdb_len ) ? ATA_PT_12_CMD : ATA_PT_16_CMD ; if ( sensep && ( max_sense_len >= ( int ) sizeof ( sense_b ) ) ) { sp = sensep ; slen = max_sense_len ; } else { sp = sense_b ; slen = sizeof ( sense_b ) ; } if ( 12 == cdb_len ) memcpy ( aptCmdBlk + 1 , cdbp + 1 , ( ( cdb_len > 11 ) ? 10 : ( cdb_len - 1 ) ) ) ; else memcpy ( aptCmdBlk + 1 , cdbp + 1 , ( ( cdb_len > 15 ) ? 14 : ( cdb_len - 1 ) ) ) ; if ( verbose ) { pr2ws ( " " , cnamep ) ; for ( k = 0 ; k < cdb_len ; ++ k ) pr2ws ( " " , aptCmdBlk [ k ] ) ; pr2ws ( " \n " ) ; } ptvp = construct_scsi_pt_obj ( ) ; if ( NULL == ptvp ) { pr2ws ( " \n " , cnamep ) ; return -1 ; } set_scsi_pt_cdb ( ptvp , aptCmdBlk , cdb_len ) ; set_scsi_pt_sense ( ptvp , sp , slen ) ; if ( dlen > 0 ) { if ( dinp ) set_scsi_pt_data_in ( ptvp , ( unsigned char * ) dinp , dlen ) ; else if ( doutp ) set_scsi_pt_data_out ( ptvp , ( unsigned char * ) doutp , dlen ) ; } res = do_scsi_pt ( ptvp , sg_fd , ( ( timeout_secs > 0 ) ? timeout_secs : DEF_PT_TIMEOUT ) , verbose ) ; if ( SCSI_PT_DO_BAD_PARAMS == res ) { if ( verbose ) pr2ws ( " \n " , cnamep ) ; goto out ; } else if ( SCSI_PT_DO_TIMEOUT == res ) { if ( verbose ) pr2ws ( " \n " , cnamep ) ; goto out ; } else if ( res > 2 ) { if ( verbose ) pr2ws ( " \n " , cnamep , - res ) ; } if ( ( verbose > 2 ) && ( ( duration = get_scsi_pt_duration_ms ( ptvp ) ) >= 0 ) ) pr2ws ( " \n " , duration ) ; switch ( get_scsi_pt_result_category ( ptvp ) ) { case SCSI_PT_RESULT_GOOD : if ( ( sensep ) && ( max_sense_len > 0 ) ) * sensep = 0 ; if ( ( ata_return_dp ) && ( max_ata_return_len > 0 ) ) * ata_return_dp = 0 ; if ( residp && ( dlen > 0 ) ) * residp = get_scsi_pt_resid ( ptvp ) ; ret = 0 ; break ; case SCSI_PT_RESULT_STATUS : if ( ( sensep ) && ( max_sense_len > 0 ) ) * sensep = 0 ; if ( ( ata_return_dp ) && ( max_ata_return_len > 0 ) ) * ata_return_dp = 0 ; ret = get_scsi_pt_status_response ( ptvp ) ; break ; case SCSI_PT_RESULT_SENSE : if ( sensep && ( sp != sensep ) ) { k = get_scsi_pt_sense_len ( ptvp ) ; k = ( k > max_sense_len ) ? max_sense_len : k ; memcpy ( sensep , sp , k ) ; } if ( ata_return_dp && ( max_ata_return_len > 0 ) ) { ucp = sg_scsi_sense_desc_find ( sp , slen , 0x9 ) ; if ( ucp ) { k = ucp [ 1 ] + 2 ; k = ( k > max_ata_return_len ) ? max_ata_return_len : k ; memcpy ( ata_return_dp , ucp , k ) ; } else ata_return_dp [ 0 ] = 0x0 ; } if ( residp && ( dlen > 0 ) ) * residp = get_scsi_pt_resid ( ptvp ) ; ret = get_scsi_pt_status_response ( ptvp ) ; break ; case SCSI_PT_RESULT_TRANSPORT_ERR : if ( verbose ) pr2ws ( " \n " , cnamep , get_scsi_pt_transport_err_str ( ptvp , sizeof ( b ) , b ) ) ; break ; case SCSI_PT_RESULT_OS_ERR : if ( verbose ) pr2ws ( " \n " , cnamep , get_scsi_pt_os_err_str ( ptvp , sizeof ( b ) , b ) ) ; break ; default : if ( verbose ) pr2ws ( " \n " , cnamep , get_scsi_pt_result_category ( ptvp ) ) ; break ; } out : destruct_scsi_pt_obj ( ptvp ) ; return ret ; }
Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT).
Invokes a ATA PASS - THROUGH ( 12 or 16 ) SCSI command ( SAT ) .
/* other than GOOD + CHECK CONDITION */ /* search for ATA return descriptor */