mirror of
https://github.com/xcat2/xNBA.git
synced 2025-01-21 23:13:14 +00:00
173 lines
4.3 KiB
C
173 lines
4.3 KiB
C
#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
|