2
0
mirror of https://github.com/xcat2/xNBA.git synced 2025-01-22 07:23:23 +00:00
xNBA/src/filo/usb/usb_scsi_low.c

173 lines
4.3 KiB
C
Raw Normal View History

2005-03-08 18:53:11 +00:00
#ifdef USB_DISK
/*******************************************************************************
*
*
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
* LinuxLabs http://www.linuxlabs.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
******************************************************************************/
#include <etherboot.h>
#include <pci.h>
#include <timer.h>
#include <lib.h>
#define DEBUG_THIS DEBUG_USB
#include <debug.h>
#define DPRINTF debug
#define uchar uint8_t
//#include "debug_x.h"
#include "usb_scsi_low.h"
int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
#define SG_DXFER_FROM_DEV -3
#define SG_DXFER_TO_DEV -2
#define REQUEST_SENSE 0x03
#define CBW_SIG 0x43425355
typedef struct usb_cbw {
unsigned int signature;
unsigned int tag;
unsigned int transfer_len; // this is exclusive of cbw and csw
uchar res1:7;
uchar direction:1; // 1 = device to host (read)
uchar lun:4;
uchar res:4;
uchar cbw_len:5; // the length of the SCSI command
uchar res3:3;
uchar scsi_cmd[16];
} __attribute__ ((packed)) usb_cbw_t;
#define CSW_SIG 0x53425355
typedef struct usb_csw {
unsigned int signature;
unsigned int tag;
unsigned int residue;
uchar status;
} __attribute__ ((packed)) usb_csw_t;
int scsi_command( uchar device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, char *sense_data, int sense_len)
{
usb_cbw_t cbw;
usb_csw_t csw;
int ret;
memset(&cbw,0,sizeof(usb_cbw_t));
memset(&csw,0,sizeof(usb_csw_t));
cbw.signature = CBW_SIG;
cbw.tag = 777;
memcpy(cbw.scsi_cmd, cmd, cmd_len);
cbw.cbw_len = cmd_len;
if(direction == SG_DXFER_FROM_DEV)
cbw.direction=1;
cbw.transfer_len = data_len;
ret = usb_bulk_transfer(device, 2, sizeof(cbw), (uchar *) &cbw);
if(ret<0){
DPRINTF("ERROR:Bulk write:\n");
}
if(data_len) {
if(cbw.direction) {
DPRINTF("scsi_command reading %d bytes\n", data_len);
ret = usb_bulk_transfer(device, 0x81, data_len, data);
DPRINTF("scsi_command read %d bytes\n", ret);
if(ret<0 || ret <data_len) {
DPRINTF("ERROR:Bulk read data ret = %d\n", ret);
}
} else {
// DPRINTF("scsi_command writing %u bytes\n", data_len);
ret = usb_bulk_transfer(device, 0x2, data_len, data);
// DPRINTF("scsi_command wrote %u bytes\n", ret);
if(ret<0) {
DPRINTF("ERROR:Bulk write data\n");
}
}
}
// DPRINTF("scsi_command fetching csw\n");
ret = usb_bulk_transfer(device, 0x81, sizeof(csw), (uchar *) &csw);
// DPRINTF("scsi_command csw is %d bytes\n", ret);
if(ret<0 || ret < sizeof(csw)) {
DPRINTF("ERROR: Bulk read CSW ret = %d\n", ret);
return(-1);
}
if(csw.status) {
DPRINTF("CSW: residue = %08x, status = %02x\n", csw.residue, csw.status);
DPRINTF("Getting sense data\n");
request_sense( device, sense_data, sense_len);
return(-csw.status);
}
return(data_len - csw.residue);
}
int request_sense( uchar device, char *sense_data, int len)
{
usb_cbw_t cbw;
usb_csw_t csw;
int ret;
memset(&cbw,0,sizeof(usb_cbw_t));
memset(&csw,0,sizeof(usb_csw_t));
cbw.signature = CBW_SIG;
cbw.tag = 666;
cbw.scsi_cmd[0] = REQUEST_SENSE;
cbw.scsi_cmd[4] = len;
cbw.cbw_len = 6;
cbw.direction=1;
cbw.transfer_len = len;
ret = usb_bulk_transfer(device, 2, sizeof(usb_cbw_t), (uchar *) &cbw);
if(ret<0 || ret < sizeof(usb_cbw_t)) {
DPRINTF("ERROR: sense Bulk write ret = %d\n", ret);
}
ret = usb_bulk_transfer(device, 0x81, len, sense_data);
if(ret<0 || ret < len) {
DPRINTF("ERROR: sense Bulk read data ret = %d\n", ret);
}
ret = usb_bulk_transfer(device, 0x81, sizeof(usb_csw_t), (uchar *) &csw);
if(ret<0 || ret < sizeof(usb_csw_t)) {
DPRINTF("ERROR: sense Bulk read CSW ret = %d\n", ret);
}
return(-csw.status);
}
#endif