// 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);
Messung V0.5 in Prozent C=94 H=95 G=94
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland