You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
4.4 KiB
183 lines
4.4 KiB
/* |
|
* Copyright (c) 2007 Vladimir Nadvornik <nadvornik@suse.cz> |
|
* Copyright (c) 2007-2017 Dmitry V. Levin <ldv@altlinux.org> |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. The name of the author may not be used to endorse or promote products |
|
* derived from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include "defs.h" |
|
|
|
#ifdef HAVE_SCSI_SG_H |
|
# include <scsi/sg.h> |
|
#endif |
|
|
|
#include "xlat/scsi_sg_commands.h" |
|
#include "xlat/sg_scsi_reset.h" |
|
|
|
static int |
|
decode_sg_io(struct tcb *const tcp, const uint32_t iid, |
|
const kernel_ulong_t arg) |
|
{ |
|
switch (iid) { |
|
case 'S': |
|
return decode_sg_io_v3(tcp, arg); |
|
case 'Q': |
|
return decode_sg_io_v4(tcp, arg); |
|
default: |
|
tprintf("[%u]", iid); |
|
return RVAL_DECODED | 1; |
|
} |
|
|
|
} |
|
|
|
#ifdef HAVE_SCSI_SG_H |
|
|
|
static int |
|
decode_sg_scsi_id(struct tcb *const tcp, const kernel_ulong_t arg) |
|
{ |
|
struct sg_scsi_id id; |
|
|
|
if (entering(tcp)) |
|
return 0; |
|
|
|
tprints(", "); |
|
if (!umove_or_printaddr(tcp, arg, &id)) { |
|
tprintf("{host_no=%d" |
|
", channel=%d" |
|
", scsi_id=%#x" |
|
", lun=%d" |
|
", scsi_type=%#x" |
|
", h_cmd_per_lun=%hd" |
|
", d_queue_depth=%hd}", |
|
id.host_no, |
|
id.channel, |
|
id.scsi_id, |
|
id.lun, |
|
id.scsi_type, |
|
id.h_cmd_per_lun, |
|
id.d_queue_depth); |
|
} |
|
return RVAL_DECODED | 1; |
|
} |
|
|
|
#endif /* HAVE_SCSI_SG_H */ |
|
|
|
int |
|
scsi_ioctl(struct tcb *const tcp, const unsigned int code, |
|
const kernel_ulong_t arg) |
|
{ |
|
switch (code) { |
|
case SG_IO: |
|
if (entering(tcp)) { |
|
uint32_t iid; |
|
|
|
tprints(", "); |
|
if (umove_or_printaddr(tcp, arg, &iid)) { |
|
break; |
|
} else { |
|
return decode_sg_io(tcp, iid, arg); |
|
} |
|
} else { |
|
uint32_t *piid = get_tcb_priv_data(tcp); |
|
if (piid) |
|
decode_sg_io(tcp, *piid, arg); |
|
tprints("}"); |
|
break; |
|
} |
|
|
|
#ifdef HAVE_SCSI_SG_H |
|
/* returns struct sg_scsi_id */ |
|
case SG_GET_SCSI_ID: |
|
return decode_sg_scsi_id(tcp, arg); |
|
/* returns struct sg_req_info */ |
|
case SG_GET_REQUEST_TABLE: |
|
return decode_sg_req_info(tcp, arg); |
|
#endif /* HAVE_SCSI_SG_H */ |
|
|
|
/* takes a value by pointer */ |
|
case SG_SCSI_RESET: { |
|
unsigned int val; |
|
tprints(", "); |
|
if (!umove_or_printaddr(tcp, arg, &val)) { |
|
tprints("["); |
|
if (val & SG_SCSI_RESET_NO_ESCALATE) { |
|
printxval(sg_scsi_reset, |
|
SG_SCSI_RESET_NO_ESCALATE, 0); |
|
tprints("|"); |
|
} |
|
printxval(sg_scsi_reset, |
|
val & ~SG_SCSI_RESET_NO_ESCALATE, |
|
"SG_SCSI_RESET_???"); |
|
tprints("]"); |
|
|
|
} |
|
break; |
|
} |
|
|
|
/* takes a signed int by pointer */ |
|
case SG_NEXT_CMD_LEN: |
|
case SG_SET_COMMAND_Q: |
|
case SG_SET_DEBUG: |
|
case SG_SET_FORCE_LOW_DMA: |
|
case SG_SET_FORCE_PACK_ID: |
|
case SG_SET_KEEP_ORPHAN: |
|
case SG_SET_RESERVED_SIZE: |
|
case SG_SET_TIMEOUT: |
|
tprints(", "); |
|
printnum_int(tcp, arg, "%d"); |
|
break; |
|
|
|
/* returns a signed int by pointer */ |
|
case SG_EMULATED_HOST: |
|
case SG_GET_ACCESS_COUNT: |
|
case SG_GET_COMMAND_Q: |
|
case SG_GET_KEEP_ORPHAN: |
|
case SG_GET_LOW_DMA: |
|
case SG_GET_NUM_WAITING: |
|
case SG_GET_PACK_ID: |
|
case SG_GET_RESERVED_SIZE: |
|
case SG_GET_SG_TABLESIZE: |
|
case SG_GET_TRANSFORM: |
|
case SG_GET_VERSION_NUM: |
|
if (entering(tcp)) |
|
return 0; |
|
tprints(", "); |
|
printnum_int(tcp, arg, "%d"); |
|
break; |
|
|
|
/* takes an integer by value */ |
|
case SG_SET_TRANSFORM: |
|
tprintf(", %#x", (unsigned int) arg); |
|
break; |
|
|
|
/* no arguments */ |
|
case SG_GET_TIMEOUT: |
|
break; |
|
|
|
default: |
|
return RVAL_DECODED; |
|
} |
|
|
|
return RVAL_DECODED | 1; |
|
}
|
|
|