📄 sscsi.c
字号:
/*--------------------------------------------------*/
/* */
/* Module SSCSI.C */
/* */
/* SCSI utility routines for Symbios 53C8XX. */
/* */
/* Adapted from Symbios Logic */
/* Software Development Kit */
/* */
/* Project: A Programmer's Guide to SCSI */
/* Copyright (C) 1997, Brian Sawert. */
/* All rights reserved. */
/* */
/*--------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
#include <dos.h>
#include "gen_tool.h" // generic tools
#include "spci.h" // PCI definitions
#include "s8xx.h" // Symbios 8XX definitions
#include "sscsi.h" // SCSI utility definitions
#include "genscsi.h" // compiled SCRIPTS code
/*---------- defines and macros ----------*/
#define TABLE_SIZE 7 // number of table entries
enum table_offsets { // table offsets
SCSI_ID = 0,
MSGOUT_BUF,
CMD_BUF,
STAT_BUF,
MSGIN_BUF,
EXMSGIN_BUF,
DATAIN_BUF
};
/*---------- global variables ----------*/
DWORD *pscript; // pointer to script
table_entry *ptable; // pointer to table
DWORD scsi_id; // encoded SCSI ID
BYTE msgout_buf[2]; // message out buffer
BYTE cmd_buf[10]; // command buffer
BYTE stat_buf; // status byte
BYTE msgin_buf[2]; // message in buffer
BYTE exmsgin_buf[4]; // extended message buffer
BYTE datain_buf[128]; // data in buffer
BYTE block_buf[1024]; // block read buffer
BYTE sense_buf[32]; // sense data buffer
BYTE sense_key; // sense data
BYTE sense_asc;
BYTE sense_ascq;
/*---------- external variables ----------*/
/*---------- local functions ----------*/
/*---------- external functions ----------*/
/*---------- function definitions ----------*/
/*--------------------------------------------------*/
/* */
/* Routine to allocate and align buffer. */
/* */
/* Usage: DWORD *alloc_buffer(WORD size); */
/* */
/* Parameters: */
/* size: size of buffer needed */
/* */
/* Return value: */
/* Returns pointer to aligned buffer on success, */
/* 0 otherwise. */
/* */
/* Note: */
/* We never free this buffer, so we don't save */
/* the temporary pointer we use to allocate. */
/* */
/*--------------------------------------------------*/
DWORD *alloc_buffer(WORD size)
{
BYTE *pbuf; // temporary pointer
WORD seg, off; // pointer parts
DWORD *newptr = NULL;
// allocate buffer
pbuf = malloc(size + 4);
if (pbuf) {
// allocated buffer memory
// DWORD align the buffer
seg = FP_SEG(pbuf);
off = FP_OFF(pbuf);
off += (4 - (off & 0x03));
newptr = (DWORD *) MK_FP(seg, off);
}
return newptr;
}
/*--------------------------------------------------*/
/* */
/* Routine to check for completion by polling ISTAT */
/* register. */
/* */
/* Usage: int poll_istat(DWORD io_base, */
/* DWORD *vector, BYTE *dstat, BYTE *istat, */
/* WORD *sist); */
/* */
/* Parameters: */
/* io_base: host I/O base address */
/* vector: pointer to result vector */
/* dstat: pointer to DSTAT buffer */
/* istat: pointer to ISTAT buffer */
/* sist: pointer to SIEN & SIST buffers */
/* */
/* Return value: */
/* Returns 1 on success, 0 otherwise. */
/* */
/*--------------------------------------------------*/
int poll_istat(DWORD io_base, DWORD *vector,
BYTE *dstat, BYTE *istat, WORD *sist)
{
DWORD starttime;
DWORD tempsist;
// get start time
starttime = Get_Time();
// wait for interrupt or timeout
while (!(IORead8(io_base + ISTAT) & 0x3)) {
// no interrupt - check timeout
if (HasTimeElapsed(starttime, DEF_TIMEOUT)) {
// time has expired
return 0;
}
}
// got an interrupt - clear buffers
*istat = 0;
*dstat = 0;
*sist = 0;
*vector = 0xFFFFFFFFL;
while (IORead8(io_base + ISTAT) & 0x03) {
// read all interrupts
*istat |= IORead8(io_base + ISTAT);
if (*istat & 0x01) {
// DMA interrupt occurred
// read DMA status register
*dstat |= IORead8(io_base + DSTAT);
}
if (*istat & 0x02) {
// SCSI interrupt occurred
// read SCSI interrupt registers
tempsist = (IORead32(io_base + SIEN0));
*sist |= (WORD) (tempsist >> 16);
}
}
if (*dstat & C8XX_INT_SIR) {
// a script interrupt occurred
// get the result vector
*vector = IORead32(io_base + DSPS);
}
// get the DMA FIFO full bit
*dstat |= IORead8(io_base + DSTAT);
return(1);
}
/*--------------------------------------------------*/
/* */
/* Routine to set up script and data buffers. */
/* */
/* Usage: int init_buffers(void); */
/* */
/* Parameters: */
/* None */
/* */
/* Return value: */
/* Returns 1 on success, 0 otherwise. */
/* */
/*--------------------------------------------------*/
int init_buffers(void)
{
int retval = 0;
// allocate script buffer
pscript = alloc_buffer(sizeof(GEN_SCRIPT));
if (pscript) {
// allocated script memory
memcpy(pscript, GEN_SCRIPT, sizeof(GEN_SCRIPT));
// allocate table memory
ptable = (table_entry *) alloc_buffer(TABLE_SIZE *
sizeof(table_entry));
if (ptable) {
// allocated table memory
// set default select info
ptable[SCSI_ID].count = 0x33000000L;
ptable[SCSI_ID].address = 0L;
// set default message out
ptable[MSGOUT_BUF].count = 1L;
ptable[MSGOUT_BUF].address =
getPhysAddr(msgout_buf);
// set command buffer
ptable[CMD_BUF].count =
sizeof(cmd_buf);
ptable[CMD_BUF].address =
getPhysAddr(cmd_buf);
// set status buffer
ptable[STAT_BUF].count = 1L;
ptable[STAT_BUF].address =
getPhysAddr(&stat_buf);
// set message in buffer
ptable[MSGIN_BUF].count = 1L;
ptable[MSGIN_BUF].address =
getPhysAddr(msgin_buf);
// set extended message in buffer
ptable[EXMSGIN_BUF].count = 2L;
ptable[EXMSGIN_BUF].address =
getPhysAddr(exmsgin_buf);
// set data input buffer
ptable[DATAIN_BUF].count =
sizeof(datain_buf);
ptable[DATAIN_BUF].address =
getPhysAddr(datain_buf);
retval = 1;
}
}
return retval;
}
/*--------------------------------------------------*/
/* */
/* Routine to check status and retrieve sense */
/* data if available. */
/* */
/* Usage: int check_status( */
/* pci_device *ppcidev, */
/* scsi_device *pscsidev); */
/* */
/* Parameters: */
/* ppcidev: pointer to PCI device */
/* pscsidev: pointer to target SCSI device */
/* */
/* Return value: */
/* Returns error code defined in SSCSI.H */
/* */
/*--------------------------------------------------*/
int check_status(pci_device *ppcidev,
scsi_device *pscsidev)
{
int retval = ERR_OTHER;
switch (stat_buf) {
// handle status codes
case STAT_GOOD:
// command successful
retval = ERR_SUCCESS;
break;
case STAT_CHECK_CONDITION:
// sense data available
if (request_sense(ppcidev,
pscsidev) == ERR_SUCCESS) {
// got sense data
sense_key = sense_asc = sense_ascq = 0;
if ((sense_buf[0] & 0x7E) == 0x70) {
// valid sense data
sense_key = (sense_buf[2] & 0x0F);
sense_asc = sense_buf[12];
sense_ascq = sense_buf[13];
}
retval = ERR_SENSE;
}
break;
default:
break;
}
return retval;
}
/*--------------------------------------------------*/
/* */
/* Routine to execute Test Unit Ready command. */
/* */
/* Usage: int test_unit_ready( */
/* pci_device *ppcidev, */
/* scsi_device *pscsidev); */
/* */
/* Parameters: */
/* ppcidev: pointer to PCI device */
/* pscsidev: pointer to target SCSI device */
/* */
/* Return value: */
/* Returns error code defined in SSCSI.H */
/* */
/*--------------------------------------------------*/
int test_unit_ready(pci_device *ppcidev,
scsi_device *pscsidev)
{
int retval= ERR_OTHER;
BYTE dstat, istat;
WORD sist;
DWORD vector;
// set the DSA register to the table address
IOWrite32(ppcidev->io_base + DSA,
getPhysAddr(ptable));
// set selection info
ptable[SCSI_ID].count =
(0x0300L | pscsidev->targ_id) << 16;
// set identify message
ptable[MSGOUT_BUF].count = 1L;
msgout_buf[0] = 0x80;
// set command buffer for Test Unit Ready
memset(cmd_buf, 0, sizeof(cmd_buf));
ptable[CMD_BUF].count = 6L;
cmd_buf[0] = CMD_TEST_UNIT_READY;
// start script execution
IOWrite32(ppcidev->io_base + DSP,
getPhysAddr(pscript) + Ent_start_scsi);
// wait for interrupt to complete
if (poll_istat(ppcidev->io_base,
&vector, &dstat, &istat, &sist)) {
// check interrupt type
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -