Import of all sources.
This commit is contained in:
437
src/scsi/queue.h
Normal file
437
src/scsi/queue.h
Normal file
@@ -0,0 +1,437 @@
|
||||
/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
|
||||
|
||||
/*
|
||||
* QEMU version: Copy from netbsd, removed debug code, removed some of
|
||||
* the implementations. Left in singly-linked lists, lists, simple
|
||||
* queues, and tail queues.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
/*
|
||||
* This file defines four types of data structures: singly-linked lists,
|
||||
* lists, simple queues, and tail queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The
|
||||
* elements are singly linked for minimum space and pointer manipulation
|
||||
* overhead at the expense of O(n) removal for arbitrary elements. New
|
||||
* elements can be added to the list after an existing element or at the
|
||||
* head of the list. Elements being removed from the head of the list
|
||||
* should use the explicit macro for this purpose for optimum
|
||||
* efficiency. A singly-linked list may only be traversed in the forward
|
||||
* direction. Singly-linked lists are ideal for applications with large
|
||||
* datasets and few or no removals or for implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define QLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define QLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define QLIST_INIT(head) do { \
|
||||
(head)->lh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_SWAP(dstlist, srclist, field) do { \
|
||||
void *tmplist; \
|
||||
tmplist = (srclist)->lh_first; \
|
||||
(srclist)->lh_first = (dstlist)->lh_first; \
|
||||
if ((srclist)->lh_first != NULL) { \
|
||||
(srclist)->lh_first->field.le_prev = &(srclist)->lh_first; \
|
||||
} \
|
||||
(dstlist)->lh_first = tmplist; \
|
||||
if ((dstlist)->lh_first != NULL) { \
|
||||
(dstlist)->lh_first->field.le_prev = &(dstlist)->lh_first; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.le_next))
|
||||
|
||||
#define QLIST_FOREACH_SAFE(var, head, field, next_var) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var) && ((next_var) = ((var)->field.le_next), 1); \
|
||||
(var) = (next_var))
|
||||
|
||||
/*
|
||||
* List access methods.
|
||||
*/
|
||||
#define QLIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
#define QLIST_FIRST(head) ((head)->lh_first)
|
||||
#define QLIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define QSLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QSLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define QSLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define QSLIST_INIT(head) do { \
|
||||
(head)->slh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD_ATOMIC(head, elm, field) do { \
|
||||
typeof(elm) save_sle_next; \
|
||||
do { \
|
||||
save_sle_next = (elm)->field.sle_next = (head)->slh_first; \
|
||||
} while (atomic_cmpxchg(&(head)->slh_first, save_sle_next, (elm)) != \
|
||||
save_sle_next); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_MOVE_ATOMIC(dest, src) do { \
|
||||
(dest)->slh_first = atomic_xchg(&(src)->slh_first, NULL); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_REMOVE_AFTER(slistelm, field) do { \
|
||||
(slistelm)->field.sle_next = \
|
||||
QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_FOREACH(var, head, field) \
|
||||
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
|
||||
|
||||
#define QSLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = QSLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = QSLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define QSLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
#define QSLIST_FIRST(head) ((head)->slh_first)
|
||||
#define QSLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define QSIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define QSIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define QSIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define QSIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_SPLIT_AFTER(head, elm, field, removed) do { \
|
||||
QSIMPLEQ_INIT(removed); \
|
||||
if (((removed)->sqh_first = (head)->sqh_first) != NULL) { \
|
||||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) { \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} \
|
||||
(removed)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->sqh_first == (elm)) { \
|
||||
QSIMPLEQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->sqh_first; \
|
||||
while (curelm->field.sqe_next != (elm)) \
|
||||
curelm = curelm->field.sqe_next; \
|
||||
if ((curelm->field.sqe_next = \
|
||||
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.sqe_next))
|
||||
|
||||
#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var) && ((next = ((var)->field.sqe_next)), 1); \
|
||||
(var) = (next))
|
||||
|
||||
#define QSIMPLEQ_CONCAT(head1, head2) do { \
|
||||
if (!QSIMPLEQ_EMPTY((head2))) { \
|
||||
*(head1)->sqh_last = (head2)->sqh_first; \
|
||||
(head1)->sqh_last = (head2)->sqh_last; \
|
||||
QSIMPLEQ_INIT((head2)); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_LAST(head, type, field) \
|
||||
(QSIMPLEQ_EMPTY((head)) ? \
|
||||
NULL : \
|
||||
((struct type *)(void *) \
|
||||
((char *)((head)->sqh_last) - offsetof(struct type, field))))
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
|
||||
#define QSIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define Q_TAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
qual type *tqh_first; /* first element */ \
|
||||
qual type *qual *tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,)
|
||||
|
||||
#define QTAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define Q_TAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
qual type *tqe_next; /* next element */ \
|
||||
qual type *qual *tqe_prev; /* address of previous next element */\
|
||||
}
|
||||
#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,)
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define QTAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.tqe_next))
|
||||
|
||||
#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var) && ((next_var) = ((var)->field.tqe_next), 1); \
|
||||
(var) = (next_var))
|
||||
|
||||
#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
|
||||
(var); \
|
||||
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
|
||||
|
||||
/*
|
||||
* Tail queue access methods.
|
||||
*/
|
||||
#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define QTAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define QTAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
#define QTAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#endif /* QEMU_SYS_QUEUE_H */
|
||||
261
src/scsi/scsi.c
Normal file
261
src/scsi/scsi.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handling of the SCSI controllers.
|
||||
*
|
||||
* Version: @(#)scsi.c 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include "../emu.h"
|
||||
#include "../mem.h"
|
||||
#include "../rom.h"
|
||||
#include "../timer.h"
|
||||
#include "../device.h"
|
||||
#include "../cdrom/cdrom.h"
|
||||
#include "../zip.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../plat.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_aha154x.h"
|
||||
#include "scsi_buslogic.h"
|
||||
#include "scsi_ncr5380.h"
|
||||
#include "scsi_ncr53c810.h"
|
||||
#ifdef WALTJE
|
||||
# include "scsi_wd33c93.h"
|
||||
#endif
|
||||
#include "scsi_x54x.h"
|
||||
|
||||
|
||||
scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX];
|
||||
#if 0
|
||||
uint8_t SCSIPhase = 0xff;
|
||||
uint8_t SCSIStatus = SCSI_STATUS_OK;
|
||||
#endif
|
||||
char scsi_fn[SCSI_NUM][512];
|
||||
uint16_t scsi_hd_location[SCSI_NUM];
|
||||
|
||||
int scsi_card_current = 0;
|
||||
int scsi_card_last = 0;
|
||||
|
||||
uint32_t SCSI_BufferLength;
|
||||
static volatile
|
||||
mutex_t *scsiMutex;
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *internal_name;
|
||||
device_t *device;
|
||||
void (*reset)(void *p);
|
||||
} SCSI_CARD;
|
||||
|
||||
|
||||
static SCSI_CARD scsi_cards[] = {
|
||||
{ "None", "none", NULL, NULL },
|
||||
{ "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, x54x_device_reset },
|
||||
{ "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, x54x_device_reset },
|
||||
{ "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, x54x_device_reset },
|
||||
{ "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, BuslogicDeviceReset },
|
||||
{ "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,BuslogicDeviceReset },
|
||||
{ "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,NULL },
|
||||
{ "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, NULL },
|
||||
{ "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, NULL },
|
||||
{ "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, NULL },
|
||||
#ifdef WALTJE_SCSI
|
||||
{ "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, NULL },
|
||||
#endif
|
||||
{ "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, x54x_device_reset },
|
||||
{ "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,BuslogicDeviceReset },
|
||||
{ "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, BuslogicDeviceReset },
|
||||
{ "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,NULL },
|
||||
{ "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,BuslogicDeviceReset },
|
||||
{ "", "", NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
scsi_card_available(int card)
|
||||
{
|
||||
if (scsi_cards[card].device)
|
||||
return(device_available(scsi_cards[card].device));
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
scsi_card_getname(int card)
|
||||
{
|
||||
return((char *)scsi_cards[card].name);
|
||||
}
|
||||
|
||||
|
||||
device_t *
|
||||
scsi_card_getdevice(int card)
|
||||
{
|
||||
return(scsi_cards[card].device);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_card_has_config(int card)
|
||||
{
|
||||
if (! scsi_cards[card].device) return(0);
|
||||
|
||||
return(scsi_cards[card].device->config ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
scsi_card_get_internal_name(int card)
|
||||
{
|
||||
return((char *)scsi_cards[card].internal_name);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_card_get_from_internal_name(char *s)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
while (strlen((char *)scsi_cards[c].internal_name)) {
|
||||
if (! strcmp((char *)scsi_cards[c].internal_name, s))
|
||||
return(c);
|
||||
c++;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
scsi_mutex(uint8_t start)
|
||||
{
|
||||
if (start)
|
||||
scsiMutex = thread_create_mutex(L"VARCem.SCSIMutex");
|
||||
else
|
||||
thread_close_mutex((mutex_t *) scsiMutex);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
scsi_card_init(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
pclog("Building SCSI hard disk map...\n");
|
||||
build_scsi_hd_map();
|
||||
pclog("Building SCSI CD-ROM map...\n");
|
||||
build_scsi_cdrom_map();
|
||||
pclog("Building SCSI ZIP map...\n");
|
||||
build_scsi_zip_map();
|
||||
|
||||
for (i=0; i<SCSI_ID_MAX; i++) {
|
||||
for (j=0; j<SCSI_LUN_MAX; j++) {
|
||||
if (scsi_hard_disks[i][j] != 0xff) {
|
||||
SCSIDevices[i][j].LunType = SCSI_DISK;
|
||||
} else if (scsi_cdrom_drives[i][j] != 0xff) {
|
||||
SCSIDevices[i][j].LunType = SCSI_CDROM;
|
||||
} else if (scsi_zip_drives[i][j] != 0xff) {
|
||||
SCSIDevices[i][j].LunType = SCSI_ZIP;
|
||||
} else {
|
||||
SCSIDevices[i][j].LunType = SCSI_NONE;
|
||||
}
|
||||
SCSIDevices[i][j].CmdBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (scsi_cards[scsi_card_current].device)
|
||||
device_add(scsi_cards[scsi_card_current].device);
|
||||
|
||||
scsi_card_last = scsi_card_current;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
scsi_card_reset(void)
|
||||
{
|
||||
void *p = NULL;
|
||||
|
||||
if (scsi_cards[scsi_card_current].device) {
|
||||
p = device_get_priv(scsi_cards[scsi_card_current].device);
|
||||
if (p != NULL) {
|
||||
if (scsi_cards[scsi_card_current].reset)
|
||||
scsi_cards[scsi_card_current].reset(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialization function for the SCSI layer */
|
||||
void
|
||||
SCSIReset(uint8_t id, uint8_t lun)
|
||||
{
|
||||
uint8_t cdrom_id = scsi_cdrom_drives[id][lun];
|
||||
uint8_t zip_id = scsi_zip_drives[id][lun];
|
||||
uint8_t hdd_id = scsi_hard_disks[id][lun];
|
||||
|
||||
if (hdd_id != 0xff) {
|
||||
scsi_hd_reset(hdd_id);
|
||||
SCSIDevices[id][lun].LunType = SCSI_DISK;
|
||||
} else {
|
||||
if (cdrom_id != 0xff) {
|
||||
cdrom_reset(cdrom_id);
|
||||
SCSIDevices[id][lun].LunType = SCSI_CDROM;
|
||||
} else if (zip_id != 0xff) {
|
||||
zip_reset(zip_id);
|
||||
SCSIDevices[id][lun].LunType = SCSI_ZIP;
|
||||
} else {
|
||||
SCSIDevices[id][lun].LunType = SCSI_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (SCSIDevices[id][lun].CmdBuffer != NULL) {
|
||||
free(SCSIDevices[id][lun].CmdBuffer);
|
||||
SCSIDevices[id][lun].CmdBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
scsi_mutex_wait(uint8_t wait)
|
||||
{
|
||||
if (wait)
|
||||
thread_wait_mutex((mutex_t *) scsiMutex);
|
||||
else
|
||||
thread_release_mutex((mutex_t *) scsiMutex);
|
||||
}
|
||||
384
src/scsi/scsi.h
Normal file
384
src/scsi/scsi.h
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* SCSI controller handler header.
|
||||
*
|
||||
* Version: @(#)scsi.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef EMU_SCSI_H
|
||||
#define EMU_SCSI_H
|
||||
|
||||
|
||||
#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT))
|
||||
|
||||
|
||||
/* Configuration. */
|
||||
#define SCSI_ID_MAX 16 /* 16 on wide buses */
|
||||
#define SCSI_LUN_MAX 8 /* always 8 */
|
||||
|
||||
|
||||
/* SCSI commands. */
|
||||
#define GPCMD_TEST_UNIT_READY 0x00
|
||||
#define GPCMD_REZERO_UNIT 0x01
|
||||
#define GPCMD_REQUEST_SENSE 0x03
|
||||
#define GPCMD_FORMAT_UNIT 0x04
|
||||
#define GPCMD_IOMEGA_SENSE 0x06
|
||||
#define GPCMD_READ_6 0x08
|
||||
#define GPCMD_WRITE_6 0x0a
|
||||
#define GPCMD_SEEK_6 0x0b
|
||||
#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c
|
||||
#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */
|
||||
#define GPCMD_INQUIRY 0x12
|
||||
#define GPCMD_VERIFY_6 0x13
|
||||
#define GPCMD_MODE_SELECT_6 0x15
|
||||
#define GPCMD_SCSI_RESERVE 0x16
|
||||
#define GPCMD_SCSI_RELEASE 0x17
|
||||
#define GPCMD_MODE_SENSE_6 0x1a
|
||||
#define GPCMD_START_STOP_UNIT 0x1b
|
||||
#define GPCMD_SEND_DIAGNOSTIC 0x1d
|
||||
#define GPCMD_PREVENT_REMOVAL 0x1e
|
||||
#define GPCMD_READ_CDROM_CAPACITY 0x25
|
||||
#define GPCMD_READ_10 0x28
|
||||
#define GPCMD_WRITE_10 0x2a
|
||||
#define GPCMD_SEEK_10 0x2b
|
||||
#define GPCMD_WRITE_AND_VERIFY_10 0x2e
|
||||
#define GPCMD_VERIFY_10 0x2f
|
||||
#define GPCMD_READ_BUFFER 0x3c
|
||||
#define GPCMD_WRITE_SAME_10 0x41
|
||||
#define GPCMD_READ_SUBCHANNEL 0x42
|
||||
#define GPCMD_READ_TOC_PMA_ATIP 0x43
|
||||
#define GPCMD_READ_HEADER 0x44
|
||||
#define GPCMD_PLAY_AUDIO_10 0x45
|
||||
#define GPCMD_GET_CONFIGURATION 0x46
|
||||
#define GPCMD_PLAY_AUDIO_MSF 0x47
|
||||
#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48
|
||||
#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||
#define GPCMD_PAUSE_RESUME 0x4b
|
||||
#define GPCMD_STOP_PLAY_SCAN 0x4e
|
||||
#define GPCMD_READ_DISC_INFORMATION 0x51
|
||||
#define GPCMD_READ_TRACK_INFORMATION 0x52
|
||||
#define GPCMD_MODE_SELECT_10 0x55
|
||||
#define GPCMD_MODE_SENSE_10 0x5a
|
||||
#define GPCMD_PLAY_AUDIO_12 0xa5
|
||||
#define GPCMD_READ_12 0xa8
|
||||
#define GPCMD_WRITE_12 0xaa
|
||||
#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */
|
||||
#define GPCMD_WRITE_AND_VERIFY_12 0xae
|
||||
#define GPCMD_VERIFY_12 0xaf
|
||||
#define GPCMD_PLAY_CD_OLD 0xb4
|
||||
#define GPCMD_READ_CD_OLD 0xb8
|
||||
#define GPCMD_READ_CD_MSF 0xb9
|
||||
#define GPCMD_SCAN 0xba
|
||||
#define GPCMD_SET_SPEED 0xbb
|
||||
#define GPCMD_PLAY_CD 0xbc
|
||||
#define GPCMD_MECHANISM_STATUS 0xbd
|
||||
#define GPCMD_READ_CD 0xbe
|
||||
#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */
|
||||
#define GPCMD_PAUSE_RESUME_ALT 0xc2
|
||||
#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */
|
||||
#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */
|
||||
|
||||
/* Mode page codes for mode sense/set */
|
||||
#define GPMODE_R_W_ERROR_PAGE 0x01
|
||||
#define GPMODE_CDROM_PAGE 0x0d
|
||||
#define GPMODE_CDROM_AUDIO_PAGE 0x0e
|
||||
#define GPMODE_CAPABILITIES_PAGE 0x2a
|
||||
#define GPMODE_ALL_PAGES 0x3f
|
||||
|
||||
/* SCSI Status Codes */
|
||||
#define SCSI_STATUS_OK 0
|
||||
#define SCSI_STATUS_CHECK_CONDITION 2
|
||||
|
||||
/* SCSI Sense Keys */
|
||||
#define SENSE_NONE 0
|
||||
#define SENSE_NOT_READY 2
|
||||
#define SENSE_ILLEGAL_REQUEST 5
|
||||
#define SENSE_UNIT_ATTENTION 6
|
||||
|
||||
/* SCSI Additional Sense Codes */
|
||||
#define ASC_AUDIO_PLAY_OPERATION 0x00
|
||||
#define ASC_NOT_READY 0x04
|
||||
#define ASC_ILLEGAL_OPCODE 0x20
|
||||
#define ASC_LBA_OUT_OF_RANGE 0x21
|
||||
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
|
||||
#define ASC_INV_LUN 0x25
|
||||
#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26
|
||||
#define ASC_WRITE_PROTECTED 0x27
|
||||
#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28
|
||||
#define ASC_CAPACITY_DATA_CHANGED 0x2A
|
||||
#define ASC_INCOMPATIBLE_FORMAT 0x30
|
||||
#define ASC_MEDIUM_NOT_PRESENT 0x3a
|
||||
#define ASC_DATA_PHASE_ERROR 0x4b
|
||||
#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64
|
||||
|
||||
#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01
|
||||
#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
|
||||
#define ASCQ_CAPACITY_DATA_CHANGED 0x09
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13
|
||||
|
||||
/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw).
|
||||
Not that it means anything */
|
||||
#define CDROM_SPEED 706 /* 0x2C2 */
|
||||
|
||||
#define BUFFER_SIZE (256*1024)
|
||||
|
||||
#define RW_DELAY (TIMER_USEC * 500)
|
||||
|
||||
/* Some generally useful CD-ROM information */
|
||||
#define CD_MINS 75 /* max. minutes per CD */
|
||||
#define CD_SECS 60 /* seconds per minute */
|
||||
#define CD_FRAMES 75 /* frames per second */
|
||||
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
|
||||
#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
|
||||
#define CD_MAX_SECTORS (CD_MAX_BYTES / 512)
|
||||
|
||||
/* Event notification classes for GET EVENT STATUS NOTIFICATION */
|
||||
#define GESN_NO_EVENTS 0
|
||||
#define GESN_OPERATIONAL_CHANGE 1
|
||||
#define GESN_POWER_MANAGEMENT 2
|
||||
#define GESN_EXTERNAL_REQUEST 3
|
||||
#define GESN_MEDIA 4
|
||||
#define GESN_MULTIPLE_HOSTS 5
|
||||
#define GESN_DEVICE_BUSY 6
|
||||
|
||||
/* Event codes for MEDIA event status notification */
|
||||
#define MEC_NO_CHANGE 0
|
||||
#define MEC_EJECT_REQUESTED 1
|
||||
#define MEC_NEW_MEDIA 2
|
||||
#define MEC_MEDIA_REMOVAL 3 /* only for media changers */
|
||||
#define MEC_MEDIA_CHANGED 4 /* only for media changers */
|
||||
#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */
|
||||
#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */
|
||||
#define MS_TRAY_OPEN 1
|
||||
#define MS_MEDIA_PRESENT 2
|
||||
|
||||
/*
|
||||
* The MMC values are not IDE specific and might need to be moved
|
||||
* to a common header if they are also needed for the SCSI emulation
|
||||
*/
|
||||
|
||||
/* Profile list from MMC-6 revision 1 table 91 */
|
||||
#define MMC_PROFILE_NONE 0x0000
|
||||
#define MMC_PROFILE_CD_ROM 0x0008
|
||||
#define MMC_PROFILE_CD_R 0x0009
|
||||
#define MMC_PROFILE_CD_RW 0x000A
|
||||
#define MMC_PROFILE_DVD_ROM 0x0010
|
||||
#define MMC_PROFILE_DVD_R_SR 0x0011
|
||||
#define MMC_PROFILE_DVD_RAM 0x0012
|
||||
#define MMC_PROFILE_DVD_RW_RO 0x0013
|
||||
#define MMC_PROFILE_DVD_RW_SR 0x0014
|
||||
#define MMC_PROFILE_DVD_R_DL_SR 0x0015
|
||||
#define MMC_PROFILE_DVD_R_DL_JR 0x0016
|
||||
#define MMC_PROFILE_DVD_RW_DL 0x0017
|
||||
#define MMC_PROFILE_DVD_DDR 0x0018
|
||||
#define MMC_PROFILE_DVD_PLUS_RW 0x001A
|
||||
#define MMC_PROFILE_DVD_PLUS_R 0x001B
|
||||
#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A
|
||||
#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B
|
||||
#define MMC_PROFILE_BD_ROM 0x0040
|
||||
#define MMC_PROFILE_BD_R_SRM 0x0041
|
||||
#define MMC_PROFILE_BD_R_RRM 0x0042
|
||||
#define MMC_PROFILE_BD_RE 0x0043
|
||||
#define MMC_PROFILE_HDDVD_ROM 0x0050
|
||||
#define MMC_PROFILE_HDDVD_R 0x0051
|
||||
#define MMC_PROFILE_HDDVD_RAM 0x0052
|
||||
#define MMC_PROFILE_HDDVD_RW 0x0053
|
||||
#define MMC_PROFILE_HDDVD_R_DL 0x0058
|
||||
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
|
||||
#define MMC_PROFILE_INVALID 0xFFFF
|
||||
|
||||
#define SCSI_ONLY 32
|
||||
#define ATAPI_ONLY 16
|
||||
#define IMPLEMENTED 8
|
||||
#define NONDATA 4
|
||||
#define CHECK_READY 2
|
||||
#define ALLOW_UA 1
|
||||
|
||||
|
||||
extern uint8_t SCSICommandTable[0x100];
|
||||
extern uint8_t mode_sense_pages[0x40];
|
||||
extern int readcdmode;
|
||||
|
||||
/* Mode sense/select stuff. */
|
||||
extern uint8_t mode_pages_in[256][256];
|
||||
extern uint8_t page_flags[256];
|
||||
extern uint8_t prefix_len;
|
||||
extern uint8_t page_current;
|
||||
#define PAGE_CHANGEABLE 1
|
||||
#define PAGE_CHANGED 2
|
||||
|
||||
struct _scsisense_ {
|
||||
uint8_t SenseBuffer[18];
|
||||
uint8_t SenseLength;
|
||||
uint8_t UnitAttention;
|
||||
uint8_t SenseKey;
|
||||
uint8_t Asc;
|
||||
uint8_t Ascq;
|
||||
} SCSISense;
|
||||
|
||||
extern int cd_status;
|
||||
extern int prev_status;
|
||||
|
||||
enum {
|
||||
SCSI_NONE = 0,
|
||||
SCSI_DISK,
|
||||
SCSI_CDROM,
|
||||
SCSI_ZIP
|
||||
};
|
||||
|
||||
#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
|
||||
|
||||
#define MSG_COMMAND_COMPLETE 0x00
|
||||
|
||||
#define BUS_DBP 0x01
|
||||
#define BUS_SEL 0x02
|
||||
#define BUS_IO 0x04
|
||||
#define BUS_CD 0x08
|
||||
#define BUS_MSG 0x10
|
||||
#define BUS_REQ 0x20
|
||||
#define BUS_BSY 0x40
|
||||
#define BUS_RST 0x80
|
||||
#define BUS_ACK 0x200
|
||||
#define BUS_ATN 0x200
|
||||
#define BUS_ARB 0x8000
|
||||
#define BUS_SETDATA(val) ((uint32_t)val << 16)
|
||||
#define BUS_GETDATA(val) ((val >> 16) & 0xff)
|
||||
#define BUS_DATAMASK 0xff0000
|
||||
|
||||
#define BUS_IDLE (1 << 31)
|
||||
|
||||
#define SCSI_PHASE_DATA_OUT 0
|
||||
#define SCSI_PHASE_DATA_IN BUS_IO
|
||||
#define SCSI_PHASE_COMMAND BUS_CD
|
||||
#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO)
|
||||
#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD)
|
||||
#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO)
|
||||
|
||||
typedef struct {
|
||||
uint8_t *CmdBuffer;
|
||||
int LunType;
|
||||
int32_t BufferLength;
|
||||
uint8_t Status;
|
||||
uint8_t Phase;
|
||||
} scsi_device_t;
|
||||
|
||||
|
||||
extern scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX];
|
||||
|
||||
extern void SCSIReset(uint8_t id, uint8_t lun);
|
||||
|
||||
extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type);
|
||||
extern int cdrom_LBAtoMSF_accurate(void);
|
||||
|
||||
extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save);
|
||||
extern int mode_select_terminate(int force);
|
||||
extern int mode_select_write(uint8_t val);
|
||||
|
||||
extern int scsi_card_current;
|
||||
|
||||
extern int scsi_card_available(int card);
|
||||
extern char *scsi_card_getname(int card);
|
||||
#ifdef EMU_DEVICE_H
|
||||
extern device_t *scsi_card_getdevice(int card);
|
||||
#endif
|
||||
extern int scsi_card_has_config(int card);
|
||||
extern char *scsi_card_get_internal_name(int card);
|
||||
extern int scsi_card_get_from_internal_name(char *s);
|
||||
extern void scsi_mutex(uint8_t start);
|
||||
extern void scsi_card_init(void);
|
||||
extern void scsi_card_reset(void);
|
||||
|
||||
extern uint8_t scsi_hard_disks[16][8];
|
||||
|
||||
extern int scsi_hd_err_stat_to_scsi(uint8_t id);
|
||||
extern int scsi_hd_phase_to_scsi(uint8_t id);
|
||||
extern int find_hdc_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun);
|
||||
extern void build_scsi_hd_map(void);
|
||||
extern void scsi_hd_reset(uint8_t id);
|
||||
extern void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length);
|
||||
extern void scsi_hd_command(uint8_t id, uint8_t *cdb);
|
||||
extern void scsi_hd_callback(uint8_t id);
|
||||
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t hi;
|
||||
uint8_t mid;
|
||||
uint8_t lo;
|
||||
} addr24;
|
||||
#pragma pack(pop)
|
||||
|
||||
#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF))
|
||||
#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0)
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Scatter/Gather Segment List Definitions
|
||||
*
|
||||
* Adapter limits
|
||||
*/
|
||||
#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint32_t Segment;
|
||||
uint32_t SegmentPointer;
|
||||
} SGE32;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
addr24 Segment;
|
||||
addr24 SegmentPointer;
|
||||
} SGE;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t pages[0x40][0x40];
|
||||
} mode_sense_pages_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#define MODE_SELECT_PHASE_IDLE 0
|
||||
#define MODE_SELECT_PHASE_HEADER 1
|
||||
#define MODE_SELECT_PHASE_BLOCK_DESC 2
|
||||
#define MODE_SELECT_PHASE_PAGE_HEADER 3
|
||||
#define MODE_SELECT_PHASE_PAGE 4
|
||||
|
||||
#endif /*EMU_SCSI_H*/
|
||||
|
||||
extern void scsi_mutex_wait(uint8_t wait);
|
||||
1181
src/scsi/scsi_aha154x.c
Normal file
1181
src/scsi/scsi_aha154x.c
Normal file
File diff suppressed because it is too large
Load Diff
49
src/scsi/scsi_aha154x.h
Normal file
49
src/scsi/scsi_aha154x.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the Adaptec 154x driver.
|
||||
*
|
||||
* Version: @(#)scsi_154x.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_AHA154X_H
|
||||
# define SCSI_AHA154X_H
|
||||
|
||||
|
||||
extern device_t aha1540b_device;
|
||||
extern device_t aha1542c_device;
|
||||
extern device_t aha1542cf_device;
|
||||
extern device_t aha1640_device;
|
||||
|
||||
extern void aha_device_reset(void *p);
|
||||
|
||||
|
||||
#endif /*SCSI_AHA154X_H*/
|
||||
389
src/scsi/scsi_bus.c
Normal file
389
src/scsi/scsi_bus.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* The generic SCSI bus operations handler.
|
||||
*
|
||||
* NOTES: For now ported from PCem with some modifications
|
||||
* but at least it's a start.
|
||||
*
|
||||
* Version: @(#)scsi_bus.c 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../emu.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_device.h"
|
||||
|
||||
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_COMMAND 1
|
||||
#define STATE_COMMANDWAIT 2
|
||||
#define STATE_DATAIN 3
|
||||
#define STATE_DATAOUT 4
|
||||
#define STATE_STATUS 5
|
||||
#define STATE_MESSAGEIN 6
|
||||
#define STATE_PHASESEL 7
|
||||
|
||||
#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
|
||||
|
||||
uint32_t SCSI_BufferLength;
|
||||
#ifdef ENABLE_SCSI_BUS_LOG
|
||||
int scsi_bus_do_log = ENABLE_SCSI_BUS_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
scsi_bus_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_SCSI_BUS_LOG
|
||||
va_list ap;
|
||||
|
||||
if (scsi_bus_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* get the length of a SCSI command based on its command byte type */
|
||||
static int get_cmd_len(int cbyte)
|
||||
{
|
||||
int len;
|
||||
int group;
|
||||
|
||||
group = (cbyte>>5) & 7;
|
||||
|
||||
if (group == 0) len = 6;
|
||||
if (group == 1 || group == 2) len = 10;
|
||||
if (group == 5) len = 12;
|
||||
|
||||
// scsi_bus_log("Command group %d, length %d\n", group, len);
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_dev_id(uint8_t data)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < SCSI_ID_MAX; c++) {
|
||||
if (data & (1 << c)) return(c);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_update(scsi_bus_t *bus, int bus_assert)
|
||||
{
|
||||
scsi_device_t *dev;
|
||||
uint8_t lun = 0;
|
||||
|
||||
if (bus_assert & BUS_ARB)
|
||||
bus->state = STATE_IDLE;
|
||||
|
||||
switch (bus->state) {
|
||||
case STATE_IDLE:
|
||||
scsi_bus_log("State Idle\n");
|
||||
bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0;
|
||||
if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) {
|
||||
uint8_t sel_data = BUS_GETDATA(bus_assert);
|
||||
|
||||
bus->dev_id = get_dev_id(sel_data);
|
||||
|
||||
if ((bus->dev_id != -1) && scsi_device_present(bus->dev_id, 0)) {
|
||||
bus->bus_out |= BUS_BSY;
|
||||
bus->state = STATE_PHASESEL;
|
||||
}
|
||||
//scsi_bus_log("Device id %i\n", bus->dev_id);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_PHASESEL:
|
||||
scsi_bus_log("State Phase Sel\n");
|
||||
if (! (bus_assert & BUS_SEL)) {
|
||||
if (! (bus_assert & BUS_ATN)) {
|
||||
if ((bus->dev_id != -1) &&
|
||||
scsi_device_present(bus->dev_id, 0)) {
|
||||
bus->state = STATE_COMMAND;
|
||||
bus->bus_out = BUS_BSY | BUS_REQ;
|
||||
bus->command_pos = 0;
|
||||
SET_BUS_STATE(bus, SCSI_PHASE_COMMAND);
|
||||
} else {
|
||||
bus->state = STATE_IDLE;
|
||||
bus->bus_out = 0;
|
||||
}
|
||||
} else
|
||||
fatal("dropped sel %x\n", bus_assert & BUS_ATN);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_COMMAND:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Command\n");
|
||||
bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert);
|
||||
|
||||
bus->clear_req = 3;
|
||||
bus->new_state = bus->bus_out & SCSI_PHASE_MESSAGE_IN;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
|
||||
if (get_cmd_len(bus->command[0]) == bus->command_pos) {
|
||||
lun = (bus->command[1] >> 5) & 7;
|
||||
bus->data_pos = 0;
|
||||
|
||||
dev = &SCSIDevices[bus->dev_id][lun];
|
||||
|
||||
scsi_bus_log("Command 0x%02X\n", bus->command[0]);
|
||||
|
||||
dev->BufferLength = -1;
|
||||
|
||||
scsi_device_command_phase0(bus->dev_id, lun,
|
||||
get_cmd_len(bus->command[0]),
|
||||
bus->command);
|
||||
|
||||
scsi_bus_log("(%02X:%02X): Command %02X: Buffer Length %i, SCSI Phase %02X\n", bus->dev_id, lun, bus->command[0], dev->BufferLength, dev->Phase);
|
||||
|
||||
if ((dev->Phase == SCSI_PHASE_DATA_IN) ||
|
||||
(dev->Phase == SCSI_PHASE_DATA_OUT)) {
|
||||
scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer);
|
||||
dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength);
|
||||
scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer);
|
||||
}
|
||||
|
||||
if (dev->Phase == SCSI_PHASE_DATA_OUT) {
|
||||
/* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */
|
||||
scsi_bus_log("Next state is data out\n");
|
||||
|
||||
bus->state = STATE_COMMANDWAIT;
|
||||
bus->clear_req = 0;
|
||||
} else {
|
||||
/* Other command - execute immediately. */
|
||||
bus->new_state = dev->Phase;
|
||||
if (dev->Phase == SCSI_PHASE_DATA_IN) {
|
||||
scsi_device_command_phase1(bus->dev_id, lun);
|
||||
}
|
||||
|
||||
bus->change_state_delay = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_COMMANDWAIT:
|
||||
bus->new_state = SCSI_PHASE_DATA_OUT;
|
||||
bus->change_state_delay = 4;
|
||||
bus->clear_req = 4;
|
||||
break;
|
||||
|
||||
case STATE_DATAIN:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Data In\n");
|
||||
|
||||
/* This seems to be read, so we first execute the command, then we return the bytes to the host. */
|
||||
|
||||
lun = (bus->command[1] >> 5) & 7;
|
||||
|
||||
dev = &SCSIDevices[bus->dev_id][lun];
|
||||
|
||||
if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) {
|
||||
free(dev->CmdBuffer);
|
||||
dev->CmdBuffer = NULL;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_STATUS;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
} else {
|
||||
uint8_t val = dev->CmdBuffer[bus->data_pos++];
|
||||
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ;
|
||||
bus->clear_req = 3;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_DATA_IN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_DATAOUT:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Data Out\n");
|
||||
|
||||
lun = (bus->command[1] >> 5) & 7;
|
||||
|
||||
dev = &SCSIDevices[bus->dev_id][lun];
|
||||
|
||||
/* This is write, so first get the data from the host, then execute the last phase of the command. */
|
||||
dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert);
|
||||
|
||||
if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) {
|
||||
/* scsi_bus_log("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */
|
||||
scsi_bus_log("Actually executing write command\n");
|
||||
scsi_device_command_phase1(bus->dev_id, lun);
|
||||
free(dev->CmdBuffer);
|
||||
dev->CmdBuffer = NULL;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_STATUS;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
} else {
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_STATUS:
|
||||
scsi_bus_log("State Status\n");
|
||||
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
/* scsi_bus_log("Preparing for message in\n"); */
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_MESSAGE_IN;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_MESSAGEIN:
|
||||
scsi_bus_log("State Message In\n");
|
||||
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = BUS_IDLE;
|
||||
bus->change_state_delay = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bus->bus_in = bus_assert;
|
||||
|
||||
return(bus->bus_out | bus->bus_in);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_read(scsi_bus_t *bus)
|
||||
{
|
||||
scsi_device_t *dev;
|
||||
uint8_t lun = 0;
|
||||
|
||||
if (bus->clear_req) {
|
||||
bus->clear_req--;
|
||||
if (!bus->clear_req) {
|
||||
scsi_bus_log("Clear REQ\n");
|
||||
|
||||
SET_BUS_STATE(bus, bus->new_state);
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->change_state_delay) {
|
||||
bus->change_state_delay--;
|
||||
if (!bus->change_state_delay) {
|
||||
uint8_t val;
|
||||
|
||||
scsi_bus_log("Change state delay\n");
|
||||
|
||||
SET_BUS_STATE(bus, bus->new_state);
|
||||
|
||||
switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) {
|
||||
case SCSI_PHASE_DATA_IN:
|
||||
lun = (bus->command[1] >> 5) & 7;
|
||||
dev = &SCSIDevices[bus->dev_id][lun];
|
||||
|
||||
scsi_bus_log("Phase data in\n");
|
||||
bus->state = STATE_DATAIN;
|
||||
val = dev->CmdBuffer[bus->data_pos++];
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP;
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_DATA_OUT:
|
||||
scsi_bus_log("Phase data out\n");
|
||||
if (bus->new_state & BUS_IDLE) {
|
||||
bus->state = STATE_IDLE;
|
||||
bus->bus_out &= ~BUS_BSY;
|
||||
} else {
|
||||
bus->state = STATE_DATAOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_STATUS:
|
||||
lun = (bus->command[1] >> 5) & 7;
|
||||
dev = &SCSIDevices[bus->dev_id][lun];
|
||||
|
||||
scsi_bus_log("Phase status\n");
|
||||
bus->state = STATE_STATUS;
|
||||
bus->bus_out |= BUS_REQ;
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP;
|
||||
/* scsi_bus_log("SCSI Status (command %02X): %02X (%08X)\n", bus->command[0], dev->Status, bus->bus_out); */
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_MESSAGE_IN:
|
||||
scsi_bus_log("Phase message in\n");
|
||||
/* scsi_bus_log("Message in\n"); */
|
||||
bus->state = STATE_MESSAGEIN;
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("change_state_delay bad state %x\n", bus->bus_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->new_req_delay) {
|
||||
bus->new_req_delay--;
|
||||
if (!bus->new_req_delay) {
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
return(bus->bus_out);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_match(scsi_bus_t *bus, int bus_assert)
|
||||
{
|
||||
return((bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) ==
|
||||
(bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)));
|
||||
}
|
||||
1829
src/scsi/scsi_buslogic.c
Normal file
1829
src/scsi/scsi_buslogic.c
Normal file
File diff suppressed because it is too large
Load Diff
49
src/scsi/scsi_buslogic.h
Normal file
49
src/scsi/scsi_buslogic.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI
|
||||
* controllers.
|
||||
*
|
||||
* Version: @(#)scsi_buslogic.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_BUSLOGIC_H
|
||||
# define SCSI_BUSLOGIC_H
|
||||
|
||||
|
||||
extern device_t buslogic_device;
|
||||
extern device_t buslogic_545s_device;
|
||||
extern device_t buslogic_640a_device;
|
||||
extern device_t buslogic_445s_device;
|
||||
extern device_t buslogic_pci_device;
|
||||
|
||||
extern void BuslogicDeviceReset(void *p);
|
||||
|
||||
|
||||
#endif /*SCSI_BUSLOGIC_H*/
|
||||
387
src/scsi/scsi_device.c
Normal file
387
src/scsi/scsi_device.c
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* The generic SCSI device command handler.
|
||||
*
|
||||
* Version: @(#)scsi_device.c 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../emu.h"
|
||||
#include "../device.h"
|
||||
#include "../cdrom/cdrom.h"
|
||||
#include "../zip.h"
|
||||
#include "../disk/hdd.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_disk.h"
|
||||
|
||||
|
||||
static uint8_t scsi_null_device_sense[14] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0 };
|
||||
|
||||
|
||||
static uint8_t scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
scsi_hd_command(id, cdb);
|
||||
return scsi_hd_err_stat_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
cdrom_command(id, cdb);
|
||||
return cdrom_CDROM_PHASE_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_ZIP)
|
||||
{
|
||||
zip_command(id, cdb);
|
||||
return zip_ZIP_PHASE_to_scsi(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SCSI_STATUS_CHECK_CONDITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void scsi_device_target_phase_callback(int lun_type, uint8_t id)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
scsi_hd_callback(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
cdrom_phase_callback(id);
|
||||
}
|
||||
else if (lun_type == SCSI_ZIP)
|
||||
{
|
||||
zip_phase_callback(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
return scsi_hd_err_stat_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
return cdrom_CDROM_PHASE_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_ZIP)
|
||||
{
|
||||
return zip_ZIP_PHASE_to_scsi(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SCSI_STATUS_CHECK_CONDITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
shdc[id].request_length = cdb_byte;
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
cdrom[id].request_length = cdb_byte;
|
||||
}
|
||||
else if (lun_type == SCSI_ZIP)
|
||||
{
|
||||
zip[id].request_length = cdb_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
return shdc[id].sense;
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
return cdrom[id].sense;
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
return zip[id].sense;
|
||||
break;
|
||||
default:
|
||||
return scsi_null_device_sense;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
scsi_hd_request_sense_for_scsi(id, buffer, alloc_length);
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
cdrom_request_sense_for_scsi(id, buffer, alloc_length);
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
zip_request_sense_for_scsi(id, buffer, alloc_length);
|
||||
break;
|
||||
default:
|
||||
memcpy(buffer, scsi_null_device_sense, alloc_length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
*type = 0x00;
|
||||
*rmb = (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 0x80 : 0x00;
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
*type = 0x05;
|
||||
*rmb = 0x80;
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
*type = 0x00;
|
||||
*rmb = 0x80;
|
||||
break;
|
||||
default:
|
||||
*type = *rmb = 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
return scsi_hd_read_capacity(id, cdb, buffer, len);
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
return cdrom_read_capacity(id, cdb, buffer, len);
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
return zip_read_capacity(id, cdb, buffer, len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_NONE:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
default:
|
||||
id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (id == 0xFF) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
return cdrom[id].cdb_len;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
return zip[id].cdb_len;
|
||||
default:
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
default:
|
||||
id = 0;
|
||||
SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_STATUS;
|
||||
SCSIDevices[scsi_id][scsi_lun].Status = SCSI_STATUS_CHECK_CONDITION;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since that field in the target struct is never used when
|
||||
* the bus type is SCSI, let's use it for this scope.
|
||||
*/
|
||||
scsi_device_target_save_cdb_byte(lun_type, id, cdb[1]);
|
||||
|
||||
if (cdb_len != 12) {
|
||||
/*
|
||||
* Make sure the LUN field of the temporary CDB is always 0,
|
||||
* otherwise Daemon Tools drives will misbehave when a command
|
||||
* is passed through to them.
|
||||
*/
|
||||
cdb[1] &= 0x1f;
|
||||
}
|
||||
|
||||
/* Finally, execute the SCSI command immediately and get the transfer length. */
|
||||
SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_COMMAND;
|
||||
SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_command(lun_type, id, cdb);
|
||||
|
||||
if (SCSIDevices[scsi_id][scsi_lun].Phase == SCSI_PHASE_STATUS) {
|
||||
/* Command completed (either OK or error) - call the phase callback to complete the command. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
}
|
||||
/* If the phase is DATA IN or DATA OUT, finish this here. */
|
||||
}
|
||||
|
||||
void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_ZIP:
|
||||
id = scsi_zip_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
default:
|
||||
id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call the second phase. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id);
|
||||
/* Command second phase complete - call the callback to complete the command. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
}
|
||||
|
||||
int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
return &SCSIDevices[scsi_id][scsi_lun].BufferLength;
|
||||
}
|
||||
81
src/scsi/scsi_device.h
Normal file
81
src/scsi/scsi_device.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the generic SCSI device command handler.
|
||||
*
|
||||
* Version: @(#)scsi_device.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_DEVICE_H
|
||||
# define SCSI_DEVICE_H
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int state;
|
||||
int new_state;
|
||||
int clear_req;
|
||||
uint32_t bus_in, bus_out;
|
||||
int dev_id;
|
||||
|
||||
int command_pos;
|
||||
uint8_t command[20];
|
||||
int data_pos;
|
||||
|
||||
int change_state_delay;
|
||||
int new_req_delay;
|
||||
} scsi_bus_t;
|
||||
|
||||
extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun);
|
||||
extern void scsi_device_type_data(uint8_t id, uint8_t lun,
|
||||
uint8_t *type, uint8_t *rmb);
|
||||
extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun,
|
||||
uint8_t *buffer,
|
||||
uint8_t alloc_length);
|
||||
extern int scsi_device_read_capacity(uint8_t id, uint8_t lun,
|
||||
uint8_t *cdb, uint8_t *buffer,
|
||||
uint32_t *len);
|
||||
extern int scsi_device_present(uint8_t id, uint8_t lun);
|
||||
extern int scsi_device_valid(uint8_t id, uint8_t lun);
|
||||
extern int scsi_device_cdb_length(uint8_t id, uint8_t lun);
|
||||
extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len,
|
||||
uint8_t *cdb);
|
||||
extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun,
|
||||
int cdb_len, uint8_t *cdb);
|
||||
extern void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun);
|
||||
extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun);
|
||||
|
||||
extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert);
|
||||
extern int scsi_bus_read(scsi_bus_t *bus);
|
||||
extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert);
|
||||
|
||||
|
||||
#endif /*SCSI_DEVICE_H*/
|
||||
1726
src/scsi/scsi_disk.c
Normal file
1726
src/scsi/scsi_disk.c
Normal file
File diff suppressed because it is too large
Load Diff
100
src/scsi/scsi_disk.h
Normal file
100
src/scsi/scsi_disk.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Emulation of SCSI fixed and removable disks.
|
||||
*
|
||||
* Version: @(#)scsi_disk.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_DISK_H
|
||||
# define SCSI_DISK_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* Stuff for SCSI hard disks. */
|
||||
uint8_t cdb[16];
|
||||
uint8_t current_cdb[16];
|
||||
uint8_t max_cdb_len;
|
||||
int requested_blocks;
|
||||
int max_blocks_at_once;
|
||||
uint16_t request_length;
|
||||
int block_total;
|
||||
int all_blocks_total;
|
||||
uint32_t packet_len;
|
||||
int packet_status;
|
||||
uint8_t status;
|
||||
uint8_t phase;
|
||||
uint32_t pos;
|
||||
int callback;
|
||||
int total_read;
|
||||
int unit_attention;
|
||||
uint8_t sense[256];
|
||||
uint8_t previous_command;
|
||||
uint8_t error;
|
||||
uint32_t sector_pos;
|
||||
uint32_t sector_len;
|
||||
uint32_t seek_pos;
|
||||
int data_pos;
|
||||
int old_len;
|
||||
int request_pos;
|
||||
uint8_t hd_cdb[16];
|
||||
|
||||
uint64_t current_page_code;
|
||||
int current_page_len;
|
||||
|
||||
int current_page_pos;
|
||||
|
||||
int mode_select_phase;
|
||||
|
||||
int total_length;
|
||||
int written_length;
|
||||
|
||||
int do_page_save;
|
||||
int block_descriptor_len;
|
||||
|
||||
uint8_t *temp_buffer;
|
||||
} scsi_hard_disk_t;
|
||||
|
||||
|
||||
extern scsi_hard_disk_t shdc[HDD_NUM];
|
||||
extern FILE *shdf[HDD_NUM];
|
||||
|
||||
|
||||
extern void scsi_disk_insert(uint8_t id);
|
||||
extern void scsi_loadhd(int scsi_id, int scsi_lun, int id);
|
||||
extern void scsi_reloadhd(int id);
|
||||
extern void scsi_unloadhd(int scsi_id, int scsi_lun, int id);
|
||||
|
||||
extern int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb,
|
||||
uint8_t *buffer, uint32_t *len);
|
||||
|
||||
|
||||
#endif /*SCSI_DISK_H*/
|
||||
1109
src/scsi/scsi_ncr5380.c
Normal file
1109
src/scsi/scsi_ncr5380.c
Normal file
File diff suppressed because it is too large
Load Diff
49
src/scsi/scsi_ncr5380.h
Normal file
49
src/scsi/scsi_ncr5380.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the NCR 5380 series of SCSI Host Adapters
|
||||
* made by NCR. These controllers were designed for
|
||||
* the ISA bus.
|
||||
*
|
||||
* Version: @(#)scsi_ncr5380.c 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_NCR5380_H
|
||||
# define SCSI_NCR5380_H
|
||||
|
||||
|
||||
extern device_t scsi_lcs6821n_device;
|
||||
extern device_t scsi_rt1000b_device;
|
||||
extern device_t scsi_t130b_device;
|
||||
extern device_t scsi_scsiat_device;
|
||||
|
||||
|
||||
#endif /*SCSI_NCR5380_H*/
|
||||
2125
src/scsi/scsi_ncr53c810.c
Normal file
2125
src/scsi/scsi_ncr53c810.c
Normal file
File diff suppressed because it is too large
Load Diff
45
src/scsi/scsi_ncr53c810.h
Normal file
45
src/scsi/scsi_ncr53c810.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the NCR 53C810 SCSI Host Adapter driver.
|
||||
*
|
||||
* Version: @(#)scsi_ncr53c810.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_NCR53C810_H
|
||||
# define SCSI_NCR53C810_H
|
||||
|
||||
|
||||
extern device_t ncr53c810_pci_device;
|
||||
|
||||
|
||||
#endif /*SCSI_NCR53C810_H*/
|
||||
2059
src/scsi/scsi_x54x.c
Normal file
2059
src/scsi/scsi_x54x.c
Normal file
File diff suppressed because it is too large
Load Diff
524
src/scsi/scsi_x54x.h
Normal file
524
src/scsi/scsi_x54x.h
Normal file
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* VARCem Virtual Archaelogical Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the common AHA/BL code.
|
||||
*
|
||||
* Version: @(#)scsi_x54x.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*
|
||||
* 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.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef SCSI_X54X_H
|
||||
# define SCSI_X54X_H
|
||||
|
||||
|
||||
#define SCSI_DELAY_TM 1 /* was 50 */
|
||||
|
||||
|
||||
#define ROM_SIZE 16384 /* one ROM is 16K */
|
||||
#define NVR_SIZE 256 /* size of NVR */
|
||||
|
||||
|
||||
/* EEPROM map and bit definitions. */
|
||||
#define EE0_HOSTID 0x07 /* EE(0) [2:0] */
|
||||
#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */
|
||||
#define EE1_IRQCH 0x07 /* EE(1) [3:0] */
|
||||
#define EE1_DMACH 0x70 /* EE(1) [7:4] */
|
||||
#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */
|
||||
#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */
|
||||
#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */
|
||||
#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */
|
||||
#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */
|
||||
#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */
|
||||
#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */
|
||||
#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */
|
||||
#define SPEED_33 0xFF
|
||||
#define SPEED_50 0x00
|
||||
#define SPEED_56 0x04
|
||||
#define SPEED_67 0x01
|
||||
#define SPEED_80 0x02
|
||||
#define SPEED_10 0x03
|
||||
#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */
|
||||
#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */
|
||||
#define EE6_TERM 0x02 /* EE(6) [1] host term enable */
|
||||
#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */
|
||||
#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */
|
||||
#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */
|
||||
#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */
|
||||
#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */
|
||||
|
||||
|
||||
/*
|
||||
* Host Adapter I/O ports.
|
||||
*
|
||||
* READ Port x+0: STATUS
|
||||
* WRITE Port x+0: CONTROL
|
||||
*
|
||||
* READ Port x+1: DATA
|
||||
* WRITE Port x+1: COMMAND
|
||||
*
|
||||
* READ Port x+2: INTERRUPT STATUS
|
||||
* WRITE Port x+2: (undefined?)
|
||||
*
|
||||
* R/W Port x+3: (undefined)
|
||||
*/
|
||||
|
||||
/* WRITE CONTROL commands. */
|
||||
#define CTRL_HRST 0x80 /* Hard reset */
|
||||
#define CTRL_SRST 0x40 /* Soft reset */
|
||||
#define CTRL_IRST 0x20 /* interrupt reset */
|
||||
#define CTRL_SCRST 0x10 /* SCSI bus reset */
|
||||
|
||||
/* READ STATUS. */
|
||||
#define STAT_STST 0x80 /* self-test in progress */
|
||||
#define STAT_DFAIL 0x40 /* internal diagnostic failure */
|
||||
#define STAT_INIT 0x20 /* mailbox initialization required */
|
||||
#define STAT_IDLE 0x10 /* HBA is idle */
|
||||
#define STAT_CDFULL 0x08 /* Command/Data output port is full */
|
||||
#define STAT_DFULL 0x04 /* Data input port is full */
|
||||
#define STAT_INVCMD 0x01 /* Invalid command */
|
||||
|
||||
/* READ/WRITE DATA. */
|
||||
#define CMD_NOP 0x00 /* No operation */
|
||||
#define CMD_MBINIT 0x01 /* mailbox initialization */
|
||||
#define CMD_START_SCSI 0x02 /* Start SCSI command */
|
||||
#define CMD_BIOSCMD 0x03 /* Execute ROM BIOS command */
|
||||
#define CMD_INQUIRY 0x04 /* Adapter inquiry */
|
||||
#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */
|
||||
#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */
|
||||
#define CMD_BUSON_TIME 0x07 /* set bus-On time */
|
||||
#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */
|
||||
#define CMD_DMASPEED 0x09 /* set ISA DMA speed */
|
||||
#define CMD_RETDEVS 0x0A /* return installed devices */
|
||||
#define CMD_RETCONF 0x0B /* return configuration data */
|
||||
#define CMD_TARGET 0x0C /* set HBA to target mode */
|
||||
#define CMD_RETSETUP 0x0D /* return setup data */
|
||||
#define CMD_WRITE_CH2 0x1A /* write channel 2 buffer */
|
||||
#define CMD_READ_CH2 0x1B /* read channel 2 buffer */
|
||||
#define CMD_ECHO 0x1F /* ECHO command data */
|
||||
#define CMD_OPTIONS 0x21 /* set adapter options */
|
||||
|
||||
/* READ INTERRUPT STATUS. */
|
||||
#define INTR_ANY 0x80 /* any interrupt */
|
||||
#define INTR_SRCD 0x08 /* SCSI reset detected */
|
||||
#define INTR_HACC 0x04 /* HA command complete */
|
||||
#define INTR_MBOA 0x02 /* MBO empty */
|
||||
#define INTR_MBIF 0x01 /* MBI full */
|
||||
|
||||
|
||||
/* Structure for the INQUIRE_SETUP_INFORMATION reply. */
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t uOffset :4,
|
||||
uTransferPeriod :3,
|
||||
fSynchronous :1;
|
||||
} ReplyInquireSetupInformationSynchronousValue;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t fSynchronousInitiationEnabled :1,
|
||||
fParityCheckingEnabled :1,
|
||||
uReserved1 :6;
|
||||
uint8_t uBusTransferRate;
|
||||
uint8_t uPreemptTimeOnBus;
|
||||
uint8_t uTimeOffBus;
|
||||
uint8_t cMailbox;
|
||||
addr24 MailboxAddress;
|
||||
ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8];
|
||||
uint8_t uDisconnectPermittedId0To7;
|
||||
uint8_t VendorSpecificData[28];
|
||||
} ReplyInquireSetupInformation;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t Count;
|
||||
addr24 Address;
|
||||
} MailboxInit_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/*
|
||||
* Mailbox Definitions.
|
||||
*
|
||||
* Mailbox Out (MBO) command values.
|
||||
*/
|
||||
#define MBO_FREE 0x00
|
||||
#define MBO_START 0x01
|
||||
#define MBO_ABORT 0x02
|
||||
|
||||
/* Mailbox In (MBI) status values. */
|
||||
#define MBI_FREE 0x00
|
||||
#define MBI_SUCCESS 0x01
|
||||
#define MBI_ABORT 0x02
|
||||
#define MBI_NOT_FOUND 0x03
|
||||
#define MBI_ERROR 0x04
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t CmdStatus;
|
||||
addr24 CCBPointer;
|
||||
} Mailbox_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint32_t CCBPointer;
|
||||
union {
|
||||
struct {
|
||||
uint8_t Reserved[3];
|
||||
uint8_t ActionCode;
|
||||
} out;
|
||||
struct {
|
||||
uint8_t HostStatus;
|
||||
uint8_t TargetStatus;
|
||||
uint8_t Reserved;
|
||||
uint8_t CompletionCode;
|
||||
} in;
|
||||
} u;
|
||||
} Mailbox32_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/*
|
||||
*
|
||||
* CCB - SCSI Command Control Block
|
||||
*
|
||||
* The CCB is a superset of the CDB (Command Descriptor Block)
|
||||
* and specifies detailed information about a SCSI command.
|
||||
*
|
||||
*/
|
||||
/* Byte 0 Command Control Block Operation Code */
|
||||
#define SCSI_INITIATOR_COMMAND 0x00
|
||||
#define TARGET_MODE_COMMAND 0x01
|
||||
#define SCATTER_GATHER_COMMAND 0x02
|
||||
#define SCSI_INITIATOR_COMMAND_RES 0x03
|
||||
#define SCATTER_GATHER_COMMAND_RES 0x04
|
||||
#define BUS_RESET 0x81
|
||||
|
||||
/* Byte 1 Address and Direction Control */
|
||||
#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */
|
||||
#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */
|
||||
#define CCB_DATA_XFER_IN 0x01
|
||||
#define CCB_DATA_XFER_OUT 0x02
|
||||
#define CCB_LUN_MASK 0x07 /* Logical Unit Number */
|
||||
|
||||
/* Byte 2 SCSI_Command_Length - Length of SCSI CDB
|
||||
Byte 3 Request Sense Allocation Length */
|
||||
#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */
|
||||
#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */
|
||||
|
||||
/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */
|
||||
/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */
|
||||
/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */
|
||||
/* Byte 13 Command Link ID - TBD (I don't know yet) */
|
||||
/* Byte 14 Host Status - Host Adapter status */
|
||||
#define CCB_COMPLETE 0x00 /* CCB completed without error */
|
||||
#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */
|
||||
#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */
|
||||
#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */
|
||||
#define CCB_DATA_OVER_UNDER_RUN 0x12
|
||||
#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */
|
||||
#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */
|
||||
#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */
|
||||
#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */
|
||||
#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */
|
||||
#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */
|
||||
#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */
|
||||
#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */
|
||||
|
||||
/* Byte 15 Target Status
|
||||
|
||||
See scsi.h files for these statuses.
|
||||
Bytes 16 and 17 Reserved (must be 0)
|
||||
Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t Opcode;
|
||||
uint8_t Reserved1 :3,
|
||||
ControlByte :2,
|
||||
TagQueued :1,
|
||||
QueueTag :2;
|
||||
uint8_t CdbLength;
|
||||
uint8_t RequestSenseLength;
|
||||
uint32_t DataLength;
|
||||
uint32_t DataPointer;
|
||||
uint8_t Reserved2[2];
|
||||
uint8_t HostStatus;
|
||||
uint8_t TargetStatus;
|
||||
uint8_t Id;
|
||||
uint8_t Lun :5,
|
||||
LegacyTagEnable :1,
|
||||
LegacyQueueTag :2;
|
||||
uint8_t Cdb[12];
|
||||
uint8_t Reserved3[6];
|
||||
uint32_t SensePointer;
|
||||
} CCB32;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t Opcode;
|
||||
uint8_t Lun :3,
|
||||
ControlByte :2,
|
||||
Id :3;
|
||||
uint8_t CdbLength;
|
||||
uint8_t RequestSenseLength;
|
||||
addr24 DataLength;
|
||||
addr24 DataPointer;
|
||||
addr24 LinkPointer;
|
||||
uint8_t LinkId;
|
||||
uint8_t HostStatus;
|
||||
uint8_t TargetStatus;
|
||||
uint8_t Reserved[2];
|
||||
uint8_t Cdb[12];
|
||||
} CCB;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t Opcode;
|
||||
uint8_t Pad1 :3,
|
||||
ControlByte :2,
|
||||
Pad2 :3;
|
||||
uint8_t CdbLength;
|
||||
uint8_t RequestSenseLength;
|
||||
uint8_t Pad3[9];
|
||||
uint8_t CompletionCode; /* Only used by the 1542C/CF(/CP?) BIOS mailboxes */
|
||||
uint8_t HostStatus;
|
||||
uint8_t TargetStatus;
|
||||
uint8_t Pad4[2];
|
||||
uint8_t Cdb[12];
|
||||
} CCBC;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef union {
|
||||
CCB32 new;
|
||||
CCB old;
|
||||
CCBC common;
|
||||
} CCBU;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
CCBU CmdBlock;
|
||||
uint8_t *RequestSenseBuffer;
|
||||
uint32_t CCBPointer;
|
||||
int Is24bit;
|
||||
uint8_t TargetID,
|
||||
LUN,
|
||||
HostStatus,
|
||||
TargetStatus,
|
||||
MailboxCompletionCode;
|
||||
} Req_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
int8_t type; /* type of device */
|
||||
|
||||
char vendor[16]; /* name of device vendor */
|
||||
char name[16]; /* name of device */
|
||||
|
||||
int8_t Irq;
|
||||
uint8_t IrqEnabled;
|
||||
|
||||
int8_t DmaChannel;
|
||||
int8_t HostID;
|
||||
uint32_t Base;
|
||||
uint8_t pos_regs[8]; /* MCA */
|
||||
|
||||
wchar_t *bios_path; /* path to BIOS image file */
|
||||
uint32_t rom_addr; /* address of BIOS ROM */
|
||||
uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */
|
||||
uint16_t rom_shram; /* index to shared RAM */
|
||||
uint16_t rom_shramsz; /* size of shared RAM */
|
||||
uint16_t rom_fwhigh; /* offset in BIOS of ver ID */
|
||||
rom_t bios; /* BIOS memory descriptor */
|
||||
rom_t uppersck; /* BIOS memory descriptor */
|
||||
uint8_t *rom1; /* main BIOS image */
|
||||
uint8_t *rom2; /* SCSI-Select image */
|
||||
|
||||
wchar_t *nvr_path; /* path to NVR image file */
|
||||
uint8_t *nvr; /* EEPROM buffer */
|
||||
|
||||
int64_t ResetCB;
|
||||
|
||||
volatile uint8_t /* for multi-threading, keep */
|
||||
Status, /* these volatile */
|
||||
Interrupt;
|
||||
|
||||
Req_t Req;
|
||||
uint8_t Geometry;
|
||||
uint8_t Control;
|
||||
uint8_t Command;
|
||||
uint8_t CmdBuf[128];
|
||||
uint8_t CmdParam;
|
||||
uint32_t CmdParamLeft;
|
||||
uint8_t DataBuf[65536];
|
||||
uint16_t DataReply;
|
||||
uint16_t DataReplyLeft;
|
||||
|
||||
volatile uint32_t
|
||||
MailboxInit,
|
||||
MailboxCount,
|
||||
MailboxOutAddr,
|
||||
MailboxOutPosCur,
|
||||
MailboxInAddr,
|
||||
MailboxInPosCur,
|
||||
MailboxReq;
|
||||
|
||||
volatile int
|
||||
Mbx24bit,
|
||||
MailboxOutInterrupts;
|
||||
|
||||
volatile int
|
||||
PendingInterrupt,
|
||||
Lock;
|
||||
|
||||
uint8_t shadow_ram[128];
|
||||
|
||||
volatile uint8_t
|
||||
MailboxIsBIOS,
|
||||
ToRaise;
|
||||
|
||||
uint8_t shram_mode;
|
||||
|
||||
uint8_t sync;
|
||||
uint8_t parity;
|
||||
|
||||
uint8_t dma_buffer[128];
|
||||
|
||||
volatile
|
||||
uint32_t BIOSMailboxInit,
|
||||
BIOSMailboxCount,
|
||||
BIOSMailboxOutAddr,
|
||||
BIOSMailboxOutPosCur,
|
||||
BIOSMailboxReq,
|
||||
Residue;
|
||||
|
||||
uint8_t BusOnTime,
|
||||
BusOffTime,
|
||||
ATBusSpeed;
|
||||
|
||||
char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */
|
||||
uint16_t bus; /* Basically a copy of device flags */
|
||||
uint8_t setup_info_len;
|
||||
uint8_t max_id;
|
||||
uint8_t pci_slot;
|
||||
uint8_t bit32;
|
||||
uint8_t lba_bios;
|
||||
|
||||
mem_mapping_t mmio_mapping;
|
||||
|
||||
uint8_t int_geom_writable;
|
||||
uint8_t cdrom_boot;
|
||||
|
||||
/* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */
|
||||
void *ven_data;
|
||||
|
||||
/* Pointer to a function that performs vendor-specific operation during the thread */
|
||||
void (*ven_thread)(void *p);
|
||||
/* Pointer to a function that executes the second parameter phase of the vendor-specific command */
|
||||
void (*ven_cmd_phase1)(void *p);
|
||||
/* Pointer to a function that gets the host adapter ID in case it has to be read from a non-standard location */
|
||||
uint8_t (*ven_get_host_id)(void *p);
|
||||
/* Pointer to a function that updates the IRQ in the vendor-specific space */
|
||||
uint8_t (*ven_get_irq)(void *p);
|
||||
/* Pointer to a function that updates the DMA channel in the vendor-specific space */
|
||||
uint8_t (*ven_get_dma)(void *p);
|
||||
/* Pointer to a function that returns whether command is fast */
|
||||
uint8_t (*ven_cmd_is_fast)(void *p);
|
||||
/* Pointer to a function that executes vendor-specific fast path commands */
|
||||
uint8_t (*ven_fast_cmds)(void *p, uint8_t cmd);
|
||||
/* Pointer to a function that gets the parameter length for vendor-specific commands */
|
||||
uint8_t (*get_ven_param_len)(void *p);
|
||||
/* Pointer to a function that executes vendor-specific commands and returns whether or not to suppress the IRQ */
|
||||
uint8_t (*ven_cmds)(void *p);
|
||||
/* Pointer to a function that fills in the vendor-specific setup data */
|
||||
void (*get_ven_data)(void *p);
|
||||
/* Pointer to a function that determines if the mode is aggressive */
|
||||
uint8_t (*is_aggressive_mode)(void *p);
|
||||
/* Pointer to a function that returns interrupt type (0 = edge, 1 = level) */
|
||||
uint8_t (*interrupt_type)(void *p);
|
||||
/* Pointer to a function that resets vendor-specific data */
|
||||
void (*ven_reset)(void *p);
|
||||
} x54x_t;
|
||||
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t command;
|
||||
uint8_t lun:3,
|
||||
reserved:2,
|
||||
id:3;
|
||||
union {
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t head;
|
||||
uint8_t sec;
|
||||
} chs;
|
||||
struct {
|
||||
uint8_t lba0; /* MSB */
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t lba3; /* LSB */
|
||||
} lba;
|
||||
} u;
|
||||
uint8_t secount;
|
||||
addr24 dma_address;
|
||||
} BIOSCMD;
|
||||
#pragma pack(pop)
|
||||
#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \
|
||||
(p->u.lba.lba2<<8) | p->u.lba.lba3)
|
||||
|
||||
|
||||
extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset);
|
||||
extern void x54x_busy(uint8_t set);
|
||||
extern void x54x_thread_start(x54x_t *dev);
|
||||
extern void x54x_set_wait_event(void);
|
||||
extern uint8_t x54x_is_busy(void);
|
||||
extern void x54x_buf_alloc(uint8_t id, uint8_t lun, int length);
|
||||
extern void x54x_buf_free(uint8_t id, uint8_t lun);
|
||||
extern uint8_t x54x_mbo_process(x54x_t *dev);
|
||||
extern void x54x_wait_for_poll(void);
|
||||
extern void x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len);
|
||||
extern void x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len);
|
||||
extern void x54x_mem_init(x54x_t *dev, uint32_t addr);
|
||||
extern void x54x_mem_enable(x54x_t *dev);
|
||||
extern void x54x_mem_set_addr(x54x_t *dev, uint32_t base);
|
||||
extern void x54x_mem_disable(x54x_t *dev);
|
||||
extern void *x54x_init(device_t *info);
|
||||
extern void x54x_close(void *priv);
|
||||
extern void x54x_device_reset(void *priv);
|
||||
|
||||
|
||||
#endif /*SCSI_X54X_H*/
|
||||
Reference in New Issue
Block a user