// SPDX-License-Identifier: GPL-2.0+ 
 | 
/* 
 | 
 * Driver for USB Mass Storage compliant devices 
 | 
 * 
 | 
 * Current development and maintenance by: 
 | 
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) 
 | 
 * 
 | 
 * Developed with the assistance of: 
 | 
 *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) 
 | 
 *   (c) 2002 Alan Stern (stern@rowland.org) 
 | 
 * 
 | 
 * Initial work by: 
 | 
 *   (c) 1999 Michael Gee (michael@linuxspecific.com) 
 | 
 * 
 | 
 * This driver is based on the 'USB Mass Storage Class' document. This 
 | 
 * describes in detail the protocol used to communicate with such 
 | 
 * devices.  Clearly, the designers had SCSI and ATAPI commands in 
 | 
 * mind when they created this document.  The commands are all very 
 | 
 * similar to commands in the SCSI-II and ATAPI specifications. 
 | 
 * 
 | 
 * It is important to note that in a number of cases this class 
 | 
 * exhibits class-specific exemptions from the USB specification. 
 | 
 * Notably the usage of NAK, STALL and ACK differs from the norm, in 
 | 
 * that they are used to communicate wait, failed and OK on commands. 
 | 
 * 
 | 
 * Also, for certain devices, the interrupt endpoint is used to convey 
 | 
 * status of a command. 
 | 
 */ 
 | 
  
 | 
#include <linux/highmem.h> 
 | 
#include <linux/export.h> 
 | 
#include <scsi/scsi.h> 
 | 
#include <scsi/scsi_cmnd.h> 
 | 
  
 | 
#include "usb.h" 
 | 
#include "protocol.h" 
 | 
#include "debug.h" 
 | 
#include "scsiglue.h" 
 | 
#include "transport.h" 
 | 
  
 | 
/*********************************************************************** 
 | 
 * Protocol routines 
 | 
 ***********************************************************************/ 
 | 
  
 | 
void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) 
 | 
{ 
 | 
    /* 
 | 
     * Pad the SCSI command with zeros out to 12 bytes.  If the 
 | 
     * command already is 12 bytes or longer, leave it alone. 
 | 
     * 
 | 
     * NOTE: This only works because a scsi_cmnd struct field contains 
 | 
     * a unsigned char cmnd[16], so we know we have storage available 
 | 
     */ 
 | 
    for (; srb->cmd_len < 12; srb->cmd_len++) 
 | 
        srb->cmnd[srb->cmd_len] = 0; 
 | 
  
 | 
    /* send the command to the transport layer */ 
 | 
    usb_stor_invoke_transport(srb, us); 
 | 
} 
 | 
  
 | 
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) 
 | 
{ 
 | 
    /* 
 | 
     * fix some commands -- this is a form of mode translation 
 | 
     * UFI devices only accept 12 byte long commands 
 | 
     * 
 | 
     * NOTE: This only works because a scsi_cmnd struct field contains 
 | 
     * a unsigned char cmnd[16], so we know we have storage available 
 | 
     */ 
 | 
  
 | 
    /* Pad the ATAPI command with zeros */ 
 | 
    for (; srb->cmd_len < 12; srb->cmd_len++) 
 | 
        srb->cmnd[srb->cmd_len] = 0; 
 | 
  
 | 
    /* set command length to 12 bytes (this affects the transport layer) */ 
 | 
    srb->cmd_len = 12; 
 | 
  
 | 
    /* XXX We should be constantly re-evaluating the need for these */ 
 | 
  
 | 
    /* determine the correct data length for these commands */ 
 | 
    switch (srb->cmnd[0]) { 
 | 
  
 | 
        /* for INQUIRY, UFI devices only ever return 36 bytes */ 
 | 
    case INQUIRY: 
 | 
        srb->cmnd[4] = 36; 
 | 
        break; 
 | 
  
 | 
        /* again, for MODE_SENSE_10, we get the minimum (8) */ 
 | 
    case MODE_SENSE_10: 
 | 
        srb->cmnd[7] = 0; 
 | 
        srb->cmnd[8] = 8; 
 | 
        break; 
 | 
  
 | 
        /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ 
 | 
    case REQUEST_SENSE: 
 | 
        srb->cmnd[4] = 18; 
 | 
        break; 
 | 
    } /* end switch on cmnd[0] */ 
 | 
  
 | 
    /* send the command to the transport layer */ 
 | 
    usb_stor_invoke_transport(srb, us); 
 | 
} 
 | 
  
 | 
void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, 
 | 
                       struct us_data *us) 
 | 
{ 
 | 
    /* send the command to the transport layer */ 
 | 
    usb_stor_invoke_transport(srb, us); 
 | 
} 
 | 
EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command); 
 | 
  
 | 
/*********************************************************************** 
 | 
 * Scatter-gather transfer buffer access routines 
 | 
 ***********************************************************************/ 
 | 
  
 | 
/* 
 | 
 * Copy a buffer of length buflen to/from the srb's transfer buffer. 
 | 
 * Update the **sgptr and *offset variables so that the next copy will 
 | 
 * pick up from where this one left off. 
 | 
 */ 
 | 
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, 
 | 
    unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr, 
 | 
    unsigned int *offset, enum xfer_buf_dir dir) 
 | 
{ 
 | 
    unsigned int cnt = 0; 
 | 
    struct scatterlist *sg = *sgptr; 
 | 
    struct sg_mapping_iter miter; 
 | 
    unsigned int nents = scsi_sg_count(srb); 
 | 
  
 | 
    if (sg) 
 | 
        nents = sg_nents(sg); 
 | 
    else 
 | 
        sg = scsi_sglist(srb); 
 | 
  
 | 
    sg_miter_start(&miter, sg, nents, dir == FROM_XFER_BUF ? 
 | 
        SG_MITER_FROM_SG: SG_MITER_TO_SG); 
 | 
  
 | 
    if (!sg_miter_skip(&miter, *offset)) 
 | 
        return cnt; 
 | 
  
 | 
    while (sg_miter_next(&miter) && cnt < buflen) { 
 | 
        unsigned int len = min_t(unsigned int, miter.length, 
 | 
                buflen - cnt); 
 | 
  
 | 
        if (dir == FROM_XFER_BUF) 
 | 
            memcpy(buffer + cnt, miter.addr, len); 
 | 
        else 
 | 
            memcpy(miter.addr, buffer + cnt, len); 
 | 
  
 | 
        if (*offset + len < miter.piter.sg->length) { 
 | 
            *offset += len; 
 | 
            *sgptr = miter.piter.sg; 
 | 
        } else { 
 | 
            *offset = 0; 
 | 
            *sgptr = sg_next(miter.piter.sg); 
 | 
        } 
 | 
        cnt += len; 
 | 
    } 
 | 
    sg_miter_stop(&miter); 
 | 
  
 | 
    return cnt; 
 | 
} 
 | 
EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf); 
 | 
  
 | 
/* 
 | 
 * Store the contents of buffer into srb's transfer buffer and set the 
 | 
 * SCSI residue. 
 | 
 */ 
 | 
void usb_stor_set_xfer_buf(unsigned char *buffer, 
 | 
    unsigned int buflen, struct scsi_cmnd *srb) 
 | 
{ 
 | 
    unsigned int offset = 0; 
 | 
    struct scatterlist *sg = NULL; 
 | 
  
 | 
    buflen = min(buflen, scsi_bufflen(srb)); 
 | 
    buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, 
 | 
            TO_XFER_BUF); 
 | 
    if (buflen < scsi_bufflen(srb)) 
 | 
        scsi_set_resid(srb, scsi_bufflen(srb) - buflen); 
 | 
} 
 | 
EXPORT_SYMBOL_GPL(usb_stor_set_xfer_buf); 
 |