mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
820 lines
21 KiB
C++
820 lines
21 KiB
C++
/*
|
|
* UAE - The Un*x Amiga Emulator
|
|
*
|
|
* a SCSI device
|
|
*
|
|
* Copyright 1995 Bernd Schmidt
|
|
* Copyright 1999 Patrick Ohly
|
|
*/
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#include "config.h"
|
|
#include "threaddep/thread.h"
|
|
#include "options.h"
|
|
#include "memory.h"
|
|
#include "custom.h"
|
|
#include "newcpu.h"
|
|
#include "disk.h"
|
|
#include "autoconf.h"
|
|
#include "filesys.h"
|
|
#include "execlib.h"
|
|
#include "native2amiga.h"
|
|
#include "scsidev.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
/* the new libscg should always have a scsi_close */
|
|
#ifndef SCSI_CLOSE
|
|
#define SCSI_CLOSE
|
|
#endif
|
|
|
|
typedef int BOOL;
|
|
|
|
#include "scg/scgcmd.h"
|
|
#include "scg/scsitransp.h"
|
|
#include "scg/scsireg.h"
|
|
|
|
/* our configure does not have a separate UAE_SCSIDEV_THREADS */
|
|
#if defined(UAE_FILESYS_THREADS) && !defined(SCSI_IS_NOT_THREAD_SAFE)
|
|
#define UAE_SCSIDEV_THREADS
|
|
#endif
|
|
|
|
#undef DEBUGME
|
|
|
|
/****************** generic SCSI stuff stolen from cdrecord and scsitransp.c ***********/
|
|
static int scsierr(SCSI *scgp)
|
|
{
|
|
register struct scg_cmd *cp = scgp->scmd;
|
|
|
|
if(cp->error != SCG_NO_ERROR ||
|
|
cp->ux_errno != 0 || *(u_char *)&cp->scb != 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int inquiry (SCSI *scgp, void *bp, int cnt)
|
|
{
|
|
struct scg_cmd *scmd = scgp->scmd;
|
|
|
|
memset(bp, cnt, '\0');
|
|
memset((caddr_t)scmd, sizeof(*scmd), '\0');
|
|
scmd->addr = bp;
|
|
scmd->size = cnt;
|
|
scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
|
|
scmd->cdb_len = SC_G0_CDBLEN;
|
|
scmd->sense_len = CCS_SENSE_LEN;
|
|
scmd->target = scgp->target;
|
|
scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
|
|
scmd->cdb.g0_cdb.lun = scgp->lun;
|
|
scmd->cdb.g0_cdb.count = cnt;
|
|
|
|
scgp->cmdname = "inquiry";
|
|
|
|
if (scsicmd(scgp) < 0)
|
|
return (-1);
|
|
return (0);
|
|
}
|
|
|
|
static void print_product(struct scsi_inquiry *ip)
|
|
{
|
|
write_log ("'%.8s' ", ip->info);
|
|
write_log ("'%.16s' ", ip->ident);
|
|
write_log ("'%.4s' ", ip->revision);
|
|
if (ip->add_len < 31) {
|
|
write_log ("NON CCS ");
|
|
}
|
|
}
|
|
|
|
/* get integer value from env or return default value, if unset */
|
|
static int getenvint (const char *varname, int def)
|
|
{
|
|
const char *val = getenv (varname);
|
|
return val ? atoi (val) : def;
|
|
}
|
|
|
|
/* wrapper for the underlying combination of scsi_smalloc()/scsi_open() */
|
|
static SCSI *openscsi (int scsibus, int target, int lun)
|
|
{
|
|
SCSI *scgp = scsi_smalloc ();
|
|
if (!scgp) {
|
|
return NULL;
|
|
}
|
|
|
|
scgp->debug = getenvint ("UAE_SCSI_DEBUG", 0);
|
|
scgp->kdebug = getenvint ("UAE_SCSI_KDEBUG", 0);
|
|
scgp->silent = getenvint ("UAE_SCSI_SILENT", 1);
|
|
scgp->verbose = getenvint ("UAE_SCSI_VERBOSE", 0);
|
|
scgp->scsibus = scsibus;
|
|
scgp->target = target;
|
|
scgp->lun = lun;
|
|
|
|
if (!scsi_open(scgp, NULL, scsibus, target, lun)) {
|
|
scsi_sfree (scgp);
|
|
return NULL;
|
|
} else {
|
|
return scgp;
|
|
}
|
|
}
|
|
|
|
static void closescsi (SCSI *scgp)
|
|
{
|
|
scsi_close (scgp);
|
|
scsi_sfree (scgp);
|
|
}
|
|
|
|
/********************* start of our own code ************************/
|
|
|
|
static int opencount = 0;
|
|
static SCSI *scgp; /* SCSI handle which is to be used by the main thread */
|
|
uae_sem_t scgp_sem;
|
|
|
|
|
|
/****************** unit handling *******************/
|
|
|
|
struct scsidevdata {
|
|
int bus, target, lun; /* the real values */
|
|
int aunit; /* Amiga unit number, by default calculated like that: */
|
|
#define BTL2UNIT(bus, target, lun) \
|
|
(2 * (bus) + (target) / 8) * 100 + \
|
|
(lun) * 10 + \
|
|
(target % 8)
|
|
SCSI *scgp;
|
|
long max_dma;
|
|
int isatapi;
|
|
#ifdef UAE_SCSIDEV_THREADS
|
|
/* Threading stuff */
|
|
smp_comm_pipe requests;
|
|
uae_thread_id tid;
|
|
int thread_running;
|
|
uae_sem_t sync_sem;
|
|
#endif
|
|
};
|
|
|
|
#define MAX_DRIVES 16
|
|
static struct scsidevdata drives[MAX_DRIVES];
|
|
static int num_drives;
|
|
static struct scsidevdata *get_scsidev_data (int unit)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_drives; i++) {
|
|
if (unit == drives[i].aunit) {
|
|
return &drives[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct scsidevdata *add_scsidev_data (int bus, int target, int lun, int aunit)
|
|
{
|
|
if (num_drives + 1 < MAX_DRIVES) {
|
|
memset(&drives[num_drives], 0, sizeof(drives[num_drives]));
|
|
drives[num_drives].bus = bus;
|
|
drives[num_drives].target = target;
|
|
drives[num_drives].lun = lun;
|
|
drives[num_drives].aunit = aunit;
|
|
#if !defined(UAE_SCSIDEV_THREADS)
|
|
drives[num_drives].scgp = scgp;
|
|
drives[num_drives].max_dma = scsi_bufsize (scgp, 512 * 1024);
|
|
#endif
|
|
/* check if this drive is an ATAPI drive */
|
|
scgp->scsibus = bus;
|
|
scgp->target = target;
|
|
scgp->lun = lun;
|
|
drives[num_drives].isatapi = scsi_isatapi (scgp);
|
|
return &drives[num_drives++];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *scsidev_thread(void *);
|
|
static int start_thread (struct scsidevdata *sdd)
|
|
{
|
|
#ifdef UAE_SCSIDEV_THREADS
|
|
if (sdd->thread_running)
|
|
return 1;
|
|
init_comm_pipe (&sdd->requests, 10, 1);
|
|
uae_sem_init (&sdd->sync_sem, 0, 0);
|
|
uae_start_thread (scsidev_thread, sdd, &sdd->tid);
|
|
uae_sem_wait (&sdd->sync_sem);
|
|
return sdd->thread_running;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
/************* Exec device functions ****************/
|
|
|
|
|
|
static uae_u32 scsidev_open (void)
|
|
{
|
|
uaecptr tmp1 = m68k_areg (regs, 1); /* IOReq */
|
|
uae_u32 unit = m68k_dreg (regs, 0);
|
|
struct scsidevdata *sdd;
|
|
|
|
#ifdef DEBUGME
|
|
printf("scsidev_open(0x%x, %d)\n", tmp1, unit);
|
|
#endif
|
|
|
|
/* Check unit number */
|
|
if ((sdd = get_scsidev_data (unit)) &&
|
|
start_thread (sdd)) {
|
|
opencount++;
|
|
put_word (m68k_areg (regs, 6)+32, get_word (m68k_areg (regs, 6)+32) + 1);
|
|
put_long (tmp1 + 24, unit); /* io_Unit */
|
|
put_byte (tmp1 + 31, 0); /* io_Error */
|
|
put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */
|
|
return 0;
|
|
}
|
|
|
|
put_long (tmp1 + 20, (uae_u32)-1);
|
|
put_byte (tmp1 + 31, (uae_u8)-1);
|
|
return (uae_u32)-1;
|
|
}
|
|
|
|
static uae_u32 scsidev_close (void)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_close()\n");
|
|
#endif
|
|
|
|
opencount--;
|
|
put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) - 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 scsidev_expunge (void)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_expunge()\n");
|
|
#endif
|
|
return 0; /* Simply ignore this one... */
|
|
}
|
|
|
|
#define MODE_SELECT_6 0x15
|
|
#define MODE_SENSE_6 0x1A
|
|
#ifndef MODE_SENSE_10
|
|
#define MODE_SELECT_10 0x55
|
|
#define MODE_SENSE_10 0x5A
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_CDR
|
|
/* please ignore this code - it can be used to debug raw CD-R writing... */
|
|
|
|
/*
|
|
** convert time in (BCD) min:sec:frame to block address
|
|
*/
|
|
typedef signed char BYTE;
|
|
typedef unsigned char UBYTE;
|
|
typedef long LONG;
|
|
typedef BYTE BCD;
|
|
typedef BYTE WORD[2];
|
|
#define BCD_DEC(x) (((x) >> 4) * 10 + ((x) & 0xF))
|
|
static LONG TestNegativeTime(LONG block)
|
|
{
|
|
/* block -151 == 99:59:74
|
|
-150 == 100:00:00 = 00:00:00 */
|
|
if (block > (97 * 60 * 75))
|
|
{
|
|
/* must be a negative block */
|
|
block -= 100 * 60 * 75;
|
|
}
|
|
return block;
|
|
}
|
|
static LONG BCDTime2Block(UBYTE min, UBYTE sec, UBYTE frame)
|
|
{
|
|
return(TestNegativeTime((LONG)((BCD_DEC(min) * 60 + BCD_DEC(sec)) * 75 + BCD_DEC(frame) - 2 * 75)));
|
|
}
|
|
static LONG Time2Block(UBYTE min, UBYTE sec, UBYTE frame)
|
|
{
|
|
return(TestNegativeTime((LONG)((min * 60 + sec) * 75 + frame - 2 * 75)));
|
|
}
|
|
static LONG BCDTime2Block_Pointer (UBYTE *p)
|
|
{
|
|
return BCDTime2Block (p[0], p[1], p[2]);
|
|
}
|
|
static LONG Time2Block_Pointer (UBYTE *p)
|
|
{
|
|
return Time2Block (p[0], p[1], p[2]);
|
|
}
|
|
#endif
|
|
|
|
static void scsidev_do_scsi (struct scsidevdata *sdd, uaecptr request)
|
|
{
|
|
SCSI *scgp = sdd->scgp;
|
|
struct scg_cmd *scmd = scgp->scmd;
|
|
uaecptr acmd = get_long (request + 40);
|
|
uaecptr scsi_data = get_long (acmd + 0);
|
|
uae_u32 scsi_len = get_long (acmd + 4);
|
|
uaecptr scsi_cmd = get_long (acmd + 12);
|
|
uae_u16 scsi_cmd_len = get_word (acmd + 16);
|
|
uae_u8 scsi_flags = get_byte (acmd + 20);
|
|
uaecptr scsi_sense = get_long (acmd + 22);
|
|
uae_u16 scsi_sense_len = get_word (acmd + 26);
|
|
int sactual = 0;
|
|
addrbank *bank_data = &get_mem_bank (scsi_data);
|
|
addrbank *bank_cmd = &get_mem_bank (scsi_cmd);
|
|
|
|
/* do transfer directly to and from Amiga memory */
|
|
if (!bank_data || !bank_data->check (scsi_data, scsi_len) ||
|
|
!bank_cmd || !bank_cmd->check (scsi_cmd, scsi_cmd_len)) {
|
|
put_byte (request + 31, (uae_u8)-5); /* IOERR_BADADDRESS */
|
|
return;
|
|
}
|
|
|
|
#ifdef SCSI_IS_NOT_THREAD_SAFE
|
|
uae_sem_wait (&scgp_sem);
|
|
#endif
|
|
|
|
scmd->timeout = 80 * 60; /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */
|
|
scmd->addr = bank_data->xlateaddr (scsi_data);
|
|
scmd->size = scsi_len;
|
|
scmd->flags = ((scsi_flags & 1) ? SCG_RECV_DATA : 0) | SCG_DISRE_ENA;
|
|
scmd->cdb_len = scsi_cmd_len;
|
|
memcpy(&scmd->cdb, bank_cmd->xlateaddr (scsi_cmd), scsi_cmd_len);
|
|
scmd->target = sdd->target;
|
|
scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
|
|
(scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
|
|
-1;
|
|
scmd->sense_count = 0;
|
|
*(uae_u8 *)&scmd->scb = 0;
|
|
|
|
#ifdef DEBUG_CDR
|
|
/* please ignore this code - it can be used to debug raw CD-R writing... */
|
|
if (!(scsi_len % 2368)) {
|
|
/* Structure for generating bytes 2353...2368 if writing in ultra raw mode */
|
|
typedef struct QDATAtag {
|
|
BYTE ControlAdr;
|
|
BCD Tno;
|
|
BCD Point;
|
|
BCD Min;
|
|
BCD Sec;
|
|
BCD Frame;
|
|
BYTE Zero;
|
|
BCD PMin;
|
|
BCD PSec;
|
|
BCD PFrame;
|
|
WORD Crc;
|
|
BYTE Reserved[3];
|
|
BYTE PChannel;
|
|
} QDATA;
|
|
|
|
int i = scsi_len / 2368;
|
|
QDATA *data = (QDATA *)&((unsigned char *)scmd->addr)[2352];
|
|
for (; i > 0; i--, data = (QDATA *)&((unsigned char *)data)[2368]) {
|
|
printf ("$%02x: $%02x $%02x | $%02x:$%02x:$%02x = %6ld | $%02x | $%02x:$%02x:$%02x = %6ld\n",
|
|
(int)data->ControlAdr, (int)*(UBYTE *)&data->Tno, (int)*(UBYTE *)&data->Point,
|
|
(int)*(UBYTE *)&data->Min, (int)*(UBYTE *)&data->Sec, (int)*(UBYTE *)&data->Frame,
|
|
BCDTime2Block_Pointer (&data->Min) + 150,
|
|
*(UBYTE *)&data->Zero,
|
|
*(UBYTE *)&data->PMin, *(UBYTE *)&data->PSec, *(UBYTE *)&data->PFrame,
|
|
BCDTime2Block_Pointer (&data->PMin));
|
|
}
|
|
fflush (stdout);
|
|
}
|
|
#endif
|
|
|
|
scgp->scsibus = sdd->bus;
|
|
scgp->target = sdd->target;
|
|
scgp->lun = sdd->lun;
|
|
scgp->cmdname = "???";
|
|
scgp->curcmdname = "???";
|
|
|
|
/* replace MODE_SELECT/SENSE_6 if we access a ATAPI drive,
|
|
otherwise send it now */
|
|
if (sdd->isatapi &&
|
|
(scmd->cdb.g0_cdb.cmd == MODE_SELECT_6 ||
|
|
scmd->cdb.g0_cdb.cmd == MODE_SENSE_6)) {
|
|
uae_u8 buffer[256 + 2], *data = scmd->addr, *tmp;
|
|
int len = 0, page_len, i;
|
|
int do_it = 1;
|
|
uae_u8 sp = scmd->cdb.g0_cdb.high_addr & 1;
|
|
uae_u8 alloc_len = scmd->cdb.g0_cdb.count;
|
|
uae_u8 pcf_page_code = scmd->cdb.g0_cdb.mid_addr;
|
|
uae_u8 cmd = scmd->cdb.g0_cdb.cmd;
|
|
|
|
memset (&scmd->cdb.g1_cdb, 0, sizeof(scmd->cdb.g1_cdb));
|
|
if (cmd == MODE_SELECT_6) {
|
|
/* expand parameter list */
|
|
tmp = data;
|
|
buffer[len++] = *tmp++; /* first byte, should be 0 */
|
|
buffer[len++] = 0; /* reserved */
|
|
buffer[len++] = *tmp++; /* medium type */
|
|
buffer[len++] = 0; *tmp++; /* ignore host application code */
|
|
for (i = 0; i < 4; i++) {
|
|
buffer[len++] = 0;
|
|
}
|
|
if (*tmp) {
|
|
/* skip block descriptor */
|
|
tmp += 8;
|
|
}
|
|
tmp++;
|
|
page_len = scsi_len - (tmp - data);
|
|
if (page_len > 0) {
|
|
memcpy (&buffer[len], tmp, page_len);
|
|
len += page_len;
|
|
|
|
scmd->cdb.g1_cdb.cmd = MODE_SELECT_10;
|
|
scmd->cdb.g1_cdb.lun = sdd->lun;
|
|
scmd->cdb.g1_cdb.res = 1 << 3; /* PF bit */
|
|
scmd->cdb.g1_cdb.reladr = sp;
|
|
scmd->cdb.g1_cdb.count[0] = len >> 8;
|
|
scmd->cdb.g1_cdb.count[1] = len;
|
|
} else {
|
|
do_it = 0;
|
|
scmd->error = 0;
|
|
*(uae_u8 *)&scmd->scb = 0;
|
|
scmd->ux_errno = 0;
|
|
}
|
|
} else {
|
|
/* MODE_SENSE_6 */
|
|
len = alloc_len + 2;
|
|
scmd->cdb.g1_cdb.cmd = MODE_SENSE_10;
|
|
scmd->cdb.g1_cdb.lun = sdd->lun;
|
|
scmd->cdb.g1_cdb.addr[0] = pcf_page_code;
|
|
scmd->cdb.g1_cdb.count[0] = len >> 8;
|
|
scmd->cdb.g1_cdb.count[1] = len;
|
|
}
|
|
if (do_it) {
|
|
scmd->cdb_len = 10;
|
|
scmd->addr = buffer;
|
|
scmd->size = len;
|
|
scmd->sense_count = 0;
|
|
*(uae_u8 *)&scmd->scb = 0;
|
|
|
|
scsicmd (scgp);
|
|
|
|
if (cmd == MODE_SENSE_6 &&
|
|
!scmd->error &&
|
|
!scmd->ux_errno &&
|
|
!*(uae_u8 *)&scmd->scb) {
|
|
int req_len = len;
|
|
|
|
/* compress result */
|
|
tmp = buffer;
|
|
len = 0;
|
|
tmp++; /* skip first byte of length - should better be zero */
|
|
data[len++] = *tmp++; /* mode data length */
|
|
data[len++] = *tmp++; /* medium type */
|
|
data[len++] = 0; /* host application type */
|
|
data[len++] = 0; /* block descr length */
|
|
tmp += 4;
|
|
if (*tmp) {
|
|
/* skip block descr - should not happen */
|
|
tmp += *tmp;
|
|
}
|
|
tmp++;
|
|
memcpy (&data[len], tmp, req_len - (tmp - buffer));
|
|
}
|
|
}
|
|
} else {
|
|
scsicmd (scgp);
|
|
}
|
|
|
|
put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */
|
|
put_byte (acmd + 21, *(uae_u8 *)&scmd->scb); /* scsi_Status */
|
|
if (*(uae_u8 *)&scmd->scb) {
|
|
put_byte (request + 31, 45); /* HFERR_BadStatus */
|
|
|
|
/* copy sense? */
|
|
for (sactual = 0;
|
|
scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count;
|
|
sactual++) {
|
|
put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]);
|
|
}
|
|
put_long (acmd + 8, 0); /* scsi_Actual */
|
|
} else {
|
|
int i;
|
|
|
|
for (i = 0; i < scsi_sense_len; i++) {
|
|
put_byte (scsi_sense + i, 0);
|
|
}
|
|
sactual = 0;
|
|
|
|
if (scmd->error != SCG_NO_ERROR ||
|
|
scmd->ux_errno != 0) {
|
|
/* we might have been limited by the hosts DMA limits,
|
|
which is usually indicated by ENOMEM */
|
|
if (scsi_len > (unsigned int)sdd->max_dma &&
|
|
scmd->ux_errno == ENOMEM) {
|
|
put_byte (request + 31, (uae_u8)-4); /* IOERR_BADLENGTH */
|
|
} else {
|
|
put_byte (request + 31, 20); /* io_Error, but not specified */
|
|
put_long (acmd + 8, 0); /* scsi_Actual */
|
|
}
|
|
} else {
|
|
put_byte (request + 31, 0);
|
|
put_long (acmd + 8, scsi_len - scmd->resid); /* scsi_Actual */
|
|
}
|
|
}
|
|
put_word (acmd + 28, sactual);
|
|
|
|
#ifdef SCSI_IS_NOT_THREAD_SAFE
|
|
uae_sem_post (&scgp_sem);
|
|
#endif
|
|
}
|
|
|
|
static void scsidev_do_io (struct scsidevdata *sdd, uaecptr request)
|
|
{
|
|
uae_u32 tmp2, dataptr, offset;
|
|
|
|
tmp2 = get_word (request+28); /* io_Command */
|
|
switch (tmp2) {
|
|
case 28:
|
|
/* HD_SCSICMD */
|
|
scsidev_do_scsi (sdd, request);
|
|
break;
|
|
default:
|
|
/* Command not understood. */
|
|
put_byte (request+31, (uae_u8)-3); /* io_Error */
|
|
break;
|
|
}
|
|
#ifdef DEBUGME
|
|
printf ("scsidev: did io: sdd = 0x%x\n", sdd);
|
|
printf ("scsidev: did io: request = %08lx\n", (unsigned long)request);
|
|
printf ("scsidev: did io: error = %d\n", (int)get_word (request+31));
|
|
#endif
|
|
}
|
|
|
|
|
|
static uae_u32 scsidev_beginio (void)
|
|
{
|
|
uae_u32 request = m68k_areg (regs, 1);
|
|
int unit = get_long (request + 24);
|
|
struct scsidevdata *sdd = get_scsidev_data (unit);
|
|
|
|
#ifdef DEBUGME
|
|
printf ("scsidev_begin_io: sdd = 0x%x\n", sdd);
|
|
printf ("scsidev_begin_io: request = %08lx\n", (unsigned long)request);
|
|
printf ("scsidev_begin_io: cmd = %d\n", (int)get_word (request+28));
|
|
#endif
|
|
|
|
put_byte (request+8, NT_MESSAGE);
|
|
put_byte (request+31, 0); /* no error yet */
|
|
|
|
#ifdef UAE_SCSIDEV_THREADS
|
|
{
|
|
uae_pt data;
|
|
|
|
/* clear IOF_QUICK */
|
|
put_byte (request+30, get_byte (request+30) & ~1);
|
|
/* forward to unit thread */
|
|
write_comm_pipe_u32 (&sdd->requests, request, 1);
|
|
return 0;
|
|
}
|
|
#else
|
|
put_byte (request+30, get_byte (request+30) & ~1);
|
|
scsidev_do_io (sdd, request);
|
|
return get_byte (request+31); /* do we really have to return io_Error? */
|
|
#endif
|
|
}
|
|
|
|
#ifdef UAE_SCSIDEV_THREADS
|
|
static void *scsidev_thread (void *sddv)
|
|
{
|
|
struct scsidevdata *sdd = sddv;
|
|
|
|
#ifdef DEBUGME
|
|
printf ("scsidev_penguin: sdd = 0x%x ready\n", sdd);
|
|
#endif
|
|
/* init SCSI */
|
|
if (!(sdd->scgp = openscsi (sdd->bus, sdd->target, sdd->lun)) ||
|
|
(sdd->max_dma = scsi_bufsize (sdd->scgp, 512 * 1024)) <= 0) {
|
|
sdd->thread_running = 0;
|
|
uae_sem_post (&sdd->sync_sem);
|
|
return 0;
|
|
}
|
|
sdd->thread_running = 1;
|
|
uae_sem_post (&sdd->sync_sem);
|
|
|
|
for (;;) {
|
|
uaecptr request;
|
|
|
|
request = (uaecptr)read_comm_pipe_u32_blocking (&sdd->requests);
|
|
#ifdef DEBUGME
|
|
printf ("scsidev_penguin: sdd = 0x%x\n", sdd);
|
|
printf ("scsidev_penguin: req = %08lx\n", (unsigned long)request);
|
|
printf ("scsidev_penguin: cmd = %d\n", (int)get_word (request+28));
|
|
#endif
|
|
if (!request) {
|
|
printf ("scsidev_penguin: going down with 0x%x\n", sdd->sync_sem);
|
|
/* Death message received. */
|
|
sdd->thread_running = 0;
|
|
uae_sem_post (&sdd->sync_sem);
|
|
/* Die. */
|
|
return 0;
|
|
}
|
|
|
|
scsidev_do_io (sdd, request);
|
|
uae_ReplyMsg (request);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
static uae_u32 scsidev_abortio (void)
|
|
{
|
|
return (uae_u32)-3;
|
|
}
|
|
|
|
static uae_u32 scsidev_init (void)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_init()\n");
|
|
#endif
|
|
|
|
if (scgp) {
|
|
/* we still have everything in place */
|
|
return m68k_dreg (regs, 0); /* device base */
|
|
}
|
|
|
|
/* init global SCSI */
|
|
if (!(scgp = openscsi (-1, -1, -1))) {
|
|
return 0;
|
|
}
|
|
|
|
uae_sem_init (&scgp_sem, 0, 1);
|
|
|
|
/* add all units we find */
|
|
for (scgp->scsibus=0; scgp->scsibus < 8; scgp->scsibus++) {
|
|
if (!scsi_havebus(scgp, scgp->scsibus))
|
|
continue;
|
|
printf("scsibus%d:\n", scgp->scsibus);
|
|
for (scgp->target=0; scgp->target < 16; scgp->target++) {
|
|
struct scsi_inquiry inq;
|
|
scgp->lun = 0;
|
|
if (inquiry (scgp, &inq, sizeof(inq))) {
|
|
continue;
|
|
}
|
|
for (scgp->lun=0; scgp->lun < 8; scgp->lun++) {
|
|
if (!inquiry (scgp, &inq, sizeof(inq))) {
|
|
int aunit = BTL2UNIT(scgp->scsibus, scgp->target, scgp->lun);
|
|
struct scsidevdata *sdd;
|
|
|
|
write_log (" %2.01d,%d (= %3.d): ", scgp->target, scgp->lun, aunit);
|
|
print_product (&inq);
|
|
sdd = add_scsidev_data (scgp->scsibus, scgp->target, scgp->lun, aunit);
|
|
write_log (!sdd ? " - init failed ???" : sdd->isatapi ? " - ATAPI" : " - SCSI");
|
|
write_log ("\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return m68k_dreg (regs, 0); /* device base */
|
|
}
|
|
|
|
static uaecptr ROM_scsidev_resname = 0,
|
|
ROM_scsidev_resid = 0,
|
|
ROM_scsidev_init = 0;
|
|
|
|
uaecptr scsidev_startup (uaecptr resaddr)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_startup(0x%x)\n", resaddr);
|
|
#endif
|
|
/* Build a struct Resident. This will set up and initialize
|
|
* the uaescsi.device */
|
|
put_word (resaddr + 0x0, 0x4AFC);
|
|
put_long (resaddr + 0x2, resaddr);
|
|
put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
|
|
put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
|
|
put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
|
|
put_long (resaddr + 0xE, ROM_scsidev_resname);
|
|
put_long (resaddr + 0x12, ROM_scsidev_resid);
|
|
put_long (resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
|
|
resaddr += 0x1A;
|
|
|
|
return resaddr;
|
|
}
|
|
|
|
void scsidev_install (void)
|
|
{
|
|
uae_u32 functable, datatable;
|
|
uae_u32 initcode, openfunc, closefunc, expungefunc;
|
|
uae_u32 beginiofunc, abortiofunc;
|
|
|
|
#ifdef DEBUGME
|
|
printf("scsidev_install(): 0x%x\n", here ());
|
|
#endif
|
|
|
|
ROM_scsidev_resname = ds ("uaescsi.device");
|
|
ROM_scsidev_resid = ds ("UAE scsi.device 0.1");
|
|
|
|
/* initcode */
|
|
initcode = here ();
|
|
calltrap (deftrap (scsidev_init)); dw (RTS);
|
|
|
|
/* Open */
|
|
openfunc = here ();
|
|
calltrap (deftrap (scsidev_open)); dw (RTS);
|
|
|
|
/* Close */
|
|
closefunc = here ();
|
|
calltrap (deftrap (scsidev_close)); dw (RTS);
|
|
|
|
/* Expunge */
|
|
expungefunc = here ();
|
|
calltrap (deftrap (scsidev_expunge)); dw (RTS);
|
|
|
|
/* BeginIO */
|
|
beginiofunc = here ();
|
|
calltrap (deftrap (scsidev_beginio));
|
|
#ifndef UAE_SCSIDEV_THREADS
|
|
/* don't reply when using threads - native2amiga's Reply() does that */
|
|
dw (0x48E7); dw (0x8002); /* movem.l d0/a6,-(a7) */
|
|
dw (0x0829); dw (0); dw (30); /* btst #0,30(a1) */
|
|
dw (0x6608); /* bne.b +8 */
|
|
dw (0x2C78); dw (0x0004); /* move.l 4,a6 */
|
|
dw (0x4EAE); dw (-378); /* jsr ReplyMsg(a6) */
|
|
dw (0x4CDF); dw (0x4001); /* movem.l (a7)+,d0/a6 */
|
|
#endif
|
|
dw (RTS);
|
|
|
|
/* AbortIO */
|
|
abortiofunc = here ();
|
|
calltrap (deftrap (scsidev_abortio)); dw (RTS);
|
|
|
|
/* FuncTable */
|
|
functable = here ();
|
|
dl (openfunc); /* Open */
|
|
dl (closefunc); /* Close */
|
|
dl (expungefunc); /* Expunge */
|
|
dl (EXPANSION_nullfunc); /* Null */
|
|
dl (beginiofunc); /* BeginIO */
|
|
dl (abortiofunc); /* AbortIO */
|
|
dl (0xFFFFFFFFul); /* end of table */
|
|
|
|
/* DataTable */
|
|
datatable = here ();
|
|
dw (0xE000); /* INITBYTE */
|
|
dw (0x0008); /* LN_TYPE */
|
|
dw (0x0300); /* NT_DEVICE */
|
|
dw (0xC000); /* INITLONG */
|
|
dw (0x000A); /* LN_NAME */
|
|
dl (ROM_scsidev_resname);
|
|
dw (0xE000); /* INITBYTE */
|
|
dw (0x000E); /* LIB_FLAGS */
|
|
dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
|
|
dw (0xD000); /* INITWORD */
|
|
dw (0x0014); /* LIB_VERSION */
|
|
dw (0x0004); /* 0.4 */
|
|
dw (0xD000); /* INITWORD */
|
|
dw (0x0016); /* LIB_REVISION */
|
|
dw (0x0000); /* end of table already ??? */
|
|
dw (0xC000); /* INITLONG */
|
|
dw (0x0018); /* LIB_IDSTRING */
|
|
dl (ROM_scsidev_resid);
|
|
dw (0x0000); /* end of table */
|
|
|
|
ROM_scsidev_init = here ();
|
|
dl (0x00000100); /* size of device base */
|
|
dl (functable);
|
|
dl (datatable);
|
|
dl (initcode);
|
|
}
|
|
|
|
void scsidev_reset (void)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_reset()\n");
|
|
#endif
|
|
|
|
#ifdef SCSI_CLOSE
|
|
#ifdef UAE_SCSIDEV_THREADS
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_drives; i++) {
|
|
if (!drives[i].thread_running) {
|
|
continue;
|
|
}
|
|
write_comm_pipe_int (&drives[i].requests, 0, 1);
|
|
uae_sem_wait (&drives[i].sync_sem);
|
|
}
|
|
num_drives = 0;
|
|
}
|
|
#endif
|
|
|
|
if (scgp) {
|
|
closescsi (scgp);
|
|
scgp = NULL;
|
|
}
|
|
#endif
|
|
|
|
opencount = 0;
|
|
}
|
|
|
|
void scsidev_start_threads (void)
|
|
{
|
|
#ifdef DEBUGME
|
|
printf("scsidev_start_threads()\n");
|
|
#endif
|
|
}
|
|
|