Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

arch_scsi_gen_disk.c

/* $Id: arch_scsi_gen_disk.c,v 1.11 2009-01-28 12:59:16 potyra Exp $ 
 *
 * Copyright (C) 2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define DEBUGPCOM 0

#ifdef INCLUDE

#include "config.h"
#include "compiler.h"
#include <stdbool.h>

#include <assert.h>
#include "fixme.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "glue-log.h"
#include "glue-main.h"
#include "glue-shm.h"
#include "glue-storage.h"

#include "sig_ide.h" /* FIXME */

#endif /* INCLUDE */

#ifdef STATE

#define BLOCKSIZE 512

struct {
      /* Config */
      int scsi_id;

      /* Process */
      struct process process;

      /* State */
      unsigned int selected;
      unsigned int lun;

      int state_atn;

      unsigned long media_blocks;
      struct storage media;

      unsigned int unit_attention;
      unsigned char sense_key; /* sense: needed for request_sense */
      unsigned char asc;       /* asc:   needed for request_sense */
      unsigned char ascq;      /* ascq:  needed for request_sense */

      uint8_t buf[0x10000];
      unsigned int count;
      unsigned int head;
      unsigned int tail;

      uint8_t msg_buf[2 + 256];
      uint8_t cmd_buf[12];
} NAME;

#endif /* STATE */

#ifdef BEHAVIOR

#define DEBUGMASK 0x00
#if 0
#define DEBUGMASK 0x0
#endif


/* SCSI bus phases... */
#define SCSI_PHASE_DATA_OUT   0x00
#define SCSI_PHASE_DATA_IN    0x01
#define SCSI_PHASE_COMMAND    0x02
#define SCSI_PHASE_STATUS     0x03
#define SCSI_PHASE_MESSAGE_OUT      0x06
#define SCSI_PHASE_MESSAGE_IN 0x07
#define SCSI_PHASE_BUSFREE    0x08

/* Add the following values together to select which debug messages you want */
#define DEBUG_PHASE           0x0001
#define DEBUG_MSG_OUT         0x0002
#define DEBUG_COMMAND         0x0004
#define DEBUG_TRANSFER        0x0008
#define DEBUG_DATA_IN         0x00010
#define DEBUG_DATA_OUT        0x00020
#define DEBUG_MISC            0x00040

/* SCSI STATI-BYTES */
#define SCSI_STATUS_GOOD      0x00
#define SCSI_STATUS_CHECK     0x01

/* SCSI MESSAGE-BYTES */
#define SCSI_CMD_COMPLETE     0x00
#define SCSI_MESSAGE_EXTENDED 0x01
#define SCSI_MESSAGE_REJECT   0x07


/* timer interval for calling the IO-controller */
#define TSYNC_INTERVAL 1000000


/* Littler helper functions,
 * stolen from Andreas diploma thesis */

/* FIX ME: BYTE ORDER ARCHITECTURE DEPENDENT!!!!*/
static void inline
put_be16(uint8_t *buf, uint16_t val)
{
      buf[0] = val >> 8;
      buf[1] = val;
}

static void inline
put_be32(uint8_t *buf, uint32_t val)
{
      buf[0] = val >> 24;
      buf[1] = val >> 16;
      buf[2] = val >> 8;
      buf[3] = val & 0xff;
}

static void
NAME_(reset)(struct cpssp *cpssp)
{
      cpssp->NAME.selected = false;
}

static void
NAME_(power_set)(struct cpssp *cpssp, unsigned int val)
{
      if (val) {
            /* Power On Event */
            NAME_(reset)(cpssp);
      
      } else {
            /* Power Off Event */
            /* Nothing to do (yet). */
      }
}

static void
NAME_(check_condition)(
      struct cpssp *s,
      unsigned char sense_key,
      unsigned char asc,
      unsigned char ascq
)
{
      s->NAME.sense_key = sense_key;
      s->NAME.asc = asc;
      s->NAME.ascq = ascq;
}

static void
NAME_(_recv)(struct cpssp *cpssp, unsigned int count)
{
      cpssp->NAME.count = count;
      cpssp->NAME.head = 0;
      cpssp->NAME.tail = 0;

      NAME_(want_recv)(cpssp, count);

      while (cpssp->NAME.head < cpssp->NAME.count) {
            sched_sleep();
      }
}

static void
NAME_(_send)(struct cpssp *cpssp, unsigned int count)
{
      cpssp->NAME.count = count;
      cpssp->NAME.head = count;
      cpssp->NAME.tail = 0;

      NAME_(want_send)(cpssp, count);

      while (cpssp->NAME.tail < cpssp->NAME.count) {
            sched_sleep();
      }
}

static void
scsi_command_test_unit_ready(struct cpssp *cpssp)
{
      /* Our unit is perfectly ready, so just send status good! */
}

static void
scsi_command_startstopunit(struct cpssp *cpssp)
{
      /* Our unit has no motor to power up/down but who cares...:*/
}

static void
scsi_command_sync_cache(struct cpssp *cpssp)
{
      /* Our cache is always synchronized */
}

static void
scsi_command_inquiry(struct cpssp *cpssp)
{
      /* Credits:
       * The following code is based on Andreas diploma-thesis
       * (user-space scsi-disk) */
      static char vendor_id[] = "FAU     ";
      static char product_id[] = "FAUmachine Disk ";
#if 0
      static char vendor_id[] = "QUANTUM ";
      static char product_id[] = "DLT7000  ";
      static char revision[] = "276A";
#endif

      int EVPD = cpssp->NAME.cmd_buf[0] & 0x01;

      assert(EVPD == 0);

      memset(cpssp->NAME.buf, 0, 8); /* Non-removable, direct-access device */

      if (0 < cpssp->NAME.lun) {
            /* no device on this lun! */
            cpssp->NAME.buf[0] = 0x7f;
      }

      cpssp->NAME.buf[2] = 2; /* ANSI SCSI level */
      cpssp->NAME.buf[3] = 2; /* SCSI-2 INQUIRY data format */
      cpssp->NAME.buf[4] = 31;      /*  Additional length */

      sprintf(cpssp->NAME.buf + 8,
            "%-8s%-16s%04x", vendor_id, product_id, 0x01);

      NAME_(phase_data_in)(cpssp);
      NAME_(_send)(cpssp, 36);
}

static void
scsi_command_mode_sense_x(struct cpssp *cpssp, int cmd_type)
{
      /* Credits:
       * The following code is based on Andreas diploma-thesis
       * (user-space scsi-disk) */

      int pc;
      int page_code;
      int changeable_values;
      int all_pages;
      uint8_t offset = 0;
      int valid_page = 0;
      int limit;
      int alloc_length = cpssp->NAME.cmd_buf[4];

      if ((cpssp->NAME.cmd_buf[1] & ~0x08) != 0) { 
            assert(0);
#if 0
            curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
            ERR("SS_INVALID_FIELD_IN_CDB: mask away DBD ( cmnd[1] & ~0x08 != 0)\n");
            return -EINVAL;
#endif
      }
      pc = cpssp->NAME.cmd_buf[2] >> 6;
      page_code = cpssp->NAME.cmd_buf[2] & 0x3f;

      if (pc == 3) { /* return saved values */
            assert(0);
#if 0
            curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
            return -EINVAL;
#endif
      }

      changeable_values = (pc == 1); /* return changeable values */
      all_pages = (page_code == 0x3f);


      /* Write the mode parameter header.  Fixed values are: default
       * medium type, no cache control (DPOFUA), and no block descriptors.
       * The only variable value is the WriteProtect bit.  We will fill in
       * the mode data length later. */

      /* clear buffer for answer-message */
      memset(cpssp->NAME.buf, 0, 32);

      /* SC_MODE_SENSE_6 */
      if (cmd_type == 6) {
            cpssp->NAME.buf[2] = 0x00;
            offset += 4;
            limit = 255;

      /* SC_MODE_SENSE_10 */
      } else {
            cpssp->NAME.buf[3] = 0x00;
            offset += 8;
            limit = 65535;
      }

      /* The mode pages, in numerical order.  The only page we support
       * is the Caching page. */
      if (page_code == 0x08 || all_pages) {
            valid_page = 1;
            cpssp->NAME.buf[offset + 0] = 0x08; /* Page code */
            cpssp->NAME.buf[offset + 1] = 10; /* Page length */

            /* None of the fields are changeable */
            memset(&cpssp->NAME.buf[offset + 2], 0, 10);

            if (!changeable_values) {
                   /* Write cache enable, */
                  cpssp->NAME.buf[offset + 2] = 0x04; 

                  /* Read cache not disabled,
                   * No cache retention priorities */
                  cpssp->NAME.buf[offset + 4] = 0xff;
                  cpssp->NAME.buf[offset + 5] = 0xff;

                  /* Maximum prefetch,
                   * Maximum prefetch ceiling */

                  cpssp->NAME.buf[offset + 8] = 0xff;
                  cpssp->NAME.buf[offset + 9] = 0xff;
                  cpssp->NAME.buf[offset + 10] = 0xff;
                  cpssp->NAME.buf[offset + 11] = 0xff;
            }
            offset += 12;
      }

      /* Check that a valid page was requested and the mode data length isn't too long. */
      if (!valid_page || offset > limit) {
            assert(0);
      }

      /*  Store the mode data length */
      if (cmd_type == 6) {
            cpssp->NAME.buf[0] = offset - 1;
      } else {
            assert(0);
            cpssp->NAME.buf[0] = offset - 2;
      }

      /* assign packet length */
      if ((alloc_length - 1) < cpssp->NAME.buf[0]) {
            cpssp->NAME.buf[0] = alloc_length - 1;
      }

        NAME_(phase_data_in)(cpssp);
      NAME_(_send)(cpssp, alloc_length);
}

static void
scsi_command_read_capacity(struct cpssp *cpssp)
{
      assert(cpssp->NAME.cmd_buf[8] == 0);

      /* return index of last-block, not no. of blocks! */
      put_be32(&cpssp->NAME.buf[0], cpssp->NAME.media_blocks - 1);

      /* BLOCK size */
      put_be32(&cpssp->NAME.buf[4], BLOCKSIZE);

        NAME_(phase_data_in)(cpssp);
      NAME_(_send)(cpssp, 8);
}

static void
scsi_command_read_x(struct cpssp *cpssp, int cmd_type)
{
      int reladdr = 0;
      uint32_t lba = 0;
      uint32_t count = 0;

      /*only read-commands >= 10 support rel-addr */
      if (cmd_type >= 10) {
            reladdr = cpssp->NAME.cmd_buf[1] & 0x01;
      }

      if (reladdr) {
            assert(0);
      }

      if  (cmd_type == 10){
            /* FIX ME: BYTE ORDER IMPORTANT!!! */
            lba |= (cpssp->NAME.cmd_buf[2] << 24);
            lba |= (cpssp->NAME.cmd_buf[3] << 16);
            lba |= (cpssp->NAME.cmd_buf[4] << 8);
            lba |= (cpssp->NAME.cmd_buf[5] << 0);

            count |= (cpssp->NAME.cmd_buf[7] << 8);
            count |= (cpssp->NAME.cmd_buf[8] << 0);
      } else if (cmd_type == 6) {
            /* FIX ME: BYTE ORDER IMPORTANT!!! */
            lba |= ((cpssp->NAME.cmd_buf[1] & 0x1f) << 16);
            lba |= (cpssp->NAME.cmd_buf[2] << 8);
            lba |= (cpssp->NAME.cmd_buf[3] << 0);

            count = cpssp->NAME.cmd_buf[4];

      } else {
            assert(0);
      }

      NAME_(phase_data_in)(cpssp);

      for ( ; 0 < count; count--) {
            storage_read_write(IO_READ, &cpssp->NAME.media, cpssp->NAME.buf,
                        (uint64_t) lba * BLOCKSIZE, BLOCKSIZE);
            NAME_(_send)(cpssp, BLOCKSIZE);
            lba++;
      }
}

static void
scsi_command_write_x(struct cpssp *cpssp, int cmd_type)
{
      int reladdr = 0;
      uint32_t lba = 0;
      uint32_t count = 0;

      /*only write-commands >= 10 support rel-addr */
      if (cmd_type >= 10) {
            reladdr = cpssp->NAME.cmd_buf[1] & 0x01;
      }

      if (reladdr) {
            assert(0);
      }

      if  (cmd_type == 10){
            /* FIX ME: BYTE ORDER IMPORTANT!!! */
            lba |= (cpssp->NAME.cmd_buf[2] << 24);
            lba |= (cpssp->NAME.cmd_buf[3] << 16);
            lba |= (cpssp->NAME.cmd_buf[4] << 8);
            lba |= (cpssp->NAME.cmd_buf[5] << 0);

            count |= (cpssp->NAME.cmd_buf[7] << 8);
            count |= (cpssp->NAME.cmd_buf[8] << 0);
      } else if (cmd_type == 6) {
            /* FIX ME: BYTE ORDER IMPORTANT!!! */
            lba |= ((cpssp->NAME.cmd_buf[1] & 0x1f) << 16);
            lba |= (cpssp->NAME.cmd_buf[2] << 8);
            lba |= (cpssp->NAME.cmd_buf[3] << 0);

            count = cpssp->NAME.cmd_buf[4];
      } else {
            assert(0);
      }

      NAME_(phase_data_out)(cpssp);

      for ( ; 0 < count; count--) {
            NAME_(_recv)(cpssp, BLOCKSIZE);
            storage_read_write(IO_WRITE, &cpssp->NAME.media,
                        cpssp->NAME.buf,
                        (uint64_t) lba * BLOCKSIZE, BLOCKSIZE);
            lba++;
      }
}

static int
NAME_(phase_select)(struct cpssp *cpssp, uint32_t id)
{
      int retval;

      if (cpssp->NAME.scsi_id == id) {
            cpssp->NAME.selected = 1;
            sched_wakeup(&cpssp->NAME.process);
            retval = 1;
      } else {
            retval = 0;
      }

      return retval;
}

#if ! defined(USB)
static int
NAME_(phase_reselect)(struct cpssp *cpssp, uint32_t id)
{
      return 0;
}
#endif

static void
NAME_(atn_set)(struct cpssp *cpssp, unsigned int val)
{
      cpssp->NAME.state_atn = val;

}

static int
NAME_(send)(struct cpssp *cpssp, const uint8_t *buf, unsigned int bufsize)
{
      if (! cpssp->NAME.selected) {
            return 0;
      }

      assert(cpssp->NAME.head + bufsize <= cpssp->NAME.count);

      memcpy(&cpssp->NAME.buf[cpssp->NAME.head], buf, bufsize);
      cpssp->NAME.head += bufsize;

      if (cpssp->NAME.head == cpssp->NAME.count) {
            sched_wakeup(&cpssp->NAME.process);
      }

      return cpssp->NAME.count - cpssp->NAME.head;
}

static int
NAME_(recv)(struct cpssp *cpssp, uint8_t *buf, unsigned int bufsize)
{
      unsigned int count;

      if (! cpssp->NAME.selected) {
            return 0;
      }

      if(cpssp->NAME.tail + bufsize <= cpssp->NAME.count) {
            count = bufsize;
      } else {
            /* some (very few) OSes seem to read data words
             * which are bigger than the available rest of
             * the input buffer (e.g. do an inw when there's
             * only one byte left). -> Read as many bytes
             * as possible and fill the rest with zeros.
             */
            assert(cpssp->NAME.count >= cpssp->NAME.tail);
            faum_log(FAUM_LOG_WARNING, __FUNCTION__, "",
                        "cannot copy requested %u byte(s)\n", bufsize);
            count = cpssp->NAME.count - cpssp->NAME.tail;
            faum_log(FAUM_LOG_WARNING, __FUNCTION__, "",
                        "-> copying %u byte(s) instead\n", count);
      }

      memcpy(buf, &cpssp->NAME.buf[cpssp->NAME.tail], count);
      memset(&buf[count], 0, bufsize-count);
      cpssp->NAME.tail += count;

      if (cpssp->NAME.tail == cpssp->NAME.count) {
            sched_wakeup(&cpssp->NAME.process);
      }

      return cpssp->NAME.count - cpssp->NAME.tail;
}

#if DEBUGPCOM
static void
printcmd_buf(struct cpssp *cpssp)
{
      unsigned int i;

      switch (cpssp->NAME.cmd_buf[0]) {
      /* winxp executes this every second... */
      case 0x00: fprintf(stderr, "TEST_UNIT_READY"); break;
      case 0x01: fprintf(stderr, "REZERO_UNIT"); break;
               /* winxp executes this way to often... */
      case 0x03: fprintf(stderr, "REQUEST_SENSE"); break;
      case 0x12: fprintf(stderr, "INQUIRY"); break;
      case 0x1a: fprintf(stderr, "MODE_SENSE_6"); break;
      case 0x1b: fprintf(stderr, "START_STOP_UNIT"); break;
      case 0x1e: fprintf(stderr, "PREVENT_ALLOW_MEDIUM_REMOVAL"); break;
      case 0x25: fprintf(stderr, "READ_CD_RECORDED_CAPACITY"); break;
      case 0x28: fprintf(stderr, "READ_10"); break;
      case 0x2a: fprintf(stderr, "WRITE_10"); break;
      case 0x2b: fprintf(stderr, "SEEK_10"); break;
      case 0x35: fprintf(stderr, "SYNCHRONIZE_CACHE"); break;
      case 0x3c: fprintf(stderr, "READ_BUFFER"); break;
      case 0x42: fprintf(stderr, "READ_SUBCHANNEL"); break;
      case 0x43: fprintf(stderr, "READ_TOC_PMA_ATIP"); break;
      case 0x46: fprintf(stderr, "GET_CONFIGURATION"); break;
      case 0x51: fprintf(stderr, "READ_DISC_INFO"); break;
      case 0x52: fprintf(stderr, "GPCMD_READ_TRACK_INFORMATION"); break;
      case 0x54: fprintf(stderr, "SEND_OPC"); break;
      case 0x55: fprintf(stderr, "MODE_SELECT_10"); break;
      case 0x5a: fprintf(stderr, "MODE_SENSE_10"); break;
      case 0x5b: fprintf(stderr, "CLOSE_TRACK"); break;
      case 0x5c: fprintf(stderr, "READ_BUFFER_CAPACITY"); break;
      case 0x5d: fprintf(stderr, "SEND_CUE_SHEET"); break;
      case 0xa0: fprintf(stderr, "REPORT_LUN"); break;
      case 0xbb: fprintf(stderr, "SET_CD_SPEED"); break;
      default: fprintf(stderr, "0x%02x", cpssp->NAME.cmd_buf[0]); break;
      }
      for (i = 1; i < 12; i++) {
            fprintf(stderr, " 0x%02x", cpssp->NAME.cmd_buf[i]);
      }
      fprintf(stderr, "\n");
}
#endif

static void
NAME_(cmd)(struct cpssp *cpssp)
{
      unsigned int lun;

#if DEBUGPCOM
      fprintf(stderr, "%s: ", __FUNCTION__);
      printcmd_buf(cpssp);
#endif

      lun = (cpssp->NAME.cmd_buf[1] >> 5) & 0x7;
      if (lun != 0 && cpssp->NAME.cmd_buf[0] != GPCMD_INQUIRY) {
            fprintf(stderr, "CD: Error: No INQUIRY and not our lun: %i\n", lun);
            /* prepare sense commands */
            /* Correct error code? FIXME */
            cpssp->NAME.sense_key = NOT_READY;
            cpssp->NAME.asc       = 0x3a;
            cpssp->NAME.ascq      = 0x00; /* FIXME */
            return;
      }

      if (cpssp->NAME.cmd_buf[0] != GPCMD_INQUIRY && cpssp->NAME.unit_attention) {
            /* power on, reset or bus device reset occured */
            NAME_(check_condition)(cpssp, UNIT_ATTENTION, 0x29, 0x00);
            cpssp->NAME.unit_attention = 0;
            return;
      }

      if (cpssp->NAME.cmd_buf[0] != GPCMD_REQUEST_SENSE) {
            /* Clear error info *before* executing command. */
            cpssp->NAME.sense_key = 0;
            cpssp->NAME.asc = 0;
            cpssp->NAME.ascq = 0;
      }

      switch (cpssp->NAME.cmd_buf[0]) {
      case 0x00: /* TEST UNIT READY */
            scsi_command_test_unit_ready(cpssp);
            break;
      case 0x08: /* READ(6) */
            scsi_command_read_x(cpssp, 6);
            break;
      case 0x1b: /* START STOP UNIT */
            scsi_command_startstopunit(cpssp);
            break;
      case 0x12: /* INQUIRY */
            scsi_command_inquiry(cpssp);
            break;
      case 0x1a: /* MODE SENSE(6) */
            scsi_command_mode_sense_x(cpssp, 6);
            break;
      case 0x25: /* READ CAPACITY */
            /* Assure PMI = 0 */
            scsi_command_read_capacity(cpssp);
            break;
      case 0x28: /* READ(10) */
            scsi_command_read_x(cpssp, 10);
            break;
      case 0x0a: /* WRITE(6) */
            scsi_command_write_x(cpssp, 6);
            break;
      case 0x2a: /* WRITE(10) */
            scsi_command_write_x(cpssp, 10);
            break;
      case 0x35: /* SYNCHRONIZE CACHE */
            scsi_command_sync_cache(cpssp);
            break;
      default:
            NAME_(check_condition)(cpssp, ILLEGAL_REQUEST, 0x20, 0x00);
            break;
      }

      if (cpssp->NAME.cmd_buf[0] == GPCMD_REQUEST_SENSE) {
            /* Clear error info *after* executing command. */
            cpssp->NAME.sense_key = 0;
            cpssp->NAME.asc = 0;
            cpssp->NAME.ascq = 0;
      }
}

static void __attribute__((__noreturn__))
NAME_(process)(void *_cpssp)
{
      struct cpssp *cpssp = _cpssp;
      uint8_t skip_remaining = 0;

      for (;;) {
            NAME_(phase_free)(cpssp);
            cpssp->NAME.selected = 0;
            sched_sleep();

            /* Message Out Phase */
            /* Message system description s2-r10l.pdf P.91 */
            NAME_(phase_msg_out)(cpssp);
            do {
                  /* Receive Message */
                  NAME_(_recv)(cpssp, 1);
                  cpssp->NAME.msg_buf[0] = cpssp->NAME.buf[0];
                  switch (cpssp->NAME.msg_buf[0]) {
                  case 0x00:
                  case 0x02 ... 0x1f:
                  case 0x80 ... 0xff:
                        /* One Byte Message */
                        break;

                  case 0x20 ... 0x2f:
                        /* Two Byte Message */
                        NAME_(_recv)(cpssp, 1);
                        cpssp->NAME.msg_buf[1] = cpssp->NAME.buf[0];
                        break;

                  case 0x01:
                        /* Extended Message */
                        cpssp->NAME.msg_buf[1] = cpssp->NAME.buf[0];
                        NAME_(_recv)(cpssp, cpssp->NAME.msg_buf[1]);
                        memcpy(&cpssp->NAME.msg_buf[2], cpssp->NAME.buf,
                                    cpssp->NAME.msg_buf[1]);
                        break;

                  default:
                        assert(0);
                  }

                  /* Process message... - FIXME */
                  if (cpssp->NAME.msg_buf[0] == 0) {
                        /* ??? Message */
                        /* FIXME */

                        /* see s2-r10l.pdf table 10 p.92ff */
                  } else if (0x80 <= cpssp->NAME.msg_buf[0]) {
                        /* IDENTIFY Message */
                        cpssp->NAME.lun = cpssp->NAME.msg_buf[0] & 0x7;

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                              && cpssp->NAME.msg_buf[1] == 0x01
                              && cpssp->NAME.msg_buf[2] == 0x00) {
                        /* ??? Message */

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                              && cpssp->NAME.msg_buf[1] == 0x01
                              && cpssp->NAME.msg_buf[2] == 0x03) {
                        /* ??? Message */
                        /* FIXME */

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                               && cpssp->NAME.msg_buf[1] == 0x01
                              && cpssp->NAME.msg_buf[2] == 0x09) {
                        /* ??? Message */

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                              && cpssp->NAME.msg_buf[1] == 0x01
                              && cpssp->NAME.msg_buf[2] == 0x19) {
                        /* ??? Message */

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                              && cpssp->NAME.msg_buf[1] == 0x06
                              && cpssp->NAME.msg_buf[2] == 0x04) {
                        /* Parallel Negotiation Message */
                        /* FIXME */

                  } else if (cpssp->NAME.msg_buf[0] == 0x01
                              && cpssp->NAME.msg_buf[1] == 0x03
                              && cpssp->NAME.msg_buf[2] == 0x01) {
                        /* Synchron Mode Negotiation Message */
                        /* FIXME */

                  } else if (cpssp->NAME.msg_buf[0] == 0x06) {
#if DEBUGPCOM
                        fprintf(stderr, "Received abort\n");
#endif
                        /* Abort */
                        skip_remaining = 1;
                        break;

                  } else if (cpssp->NAME.msg_buf[0] == 0x07) {
#if DEBUGPCOM
                        fprintf(stderr, "Received message rejected\n");
#endif
                        /* Message Rejected */
                        fixme();

                  } else if (cpssp->NAME.msg_buf[0] == 0x0c) {
#if DEBUGPCOM
                        fprintf(stderr, "Received bus device reset message\n");
#endif
                        /* Bus Device Reset Message */
                        skip_remaining = 1;
                        NAME_(reset)(cpssp); /* include unit_attention */
                        break;

                  } else {
                        fprintf(stderr, "%s: message type 0x%02x/0x%02x/0x%02x unknown.\n",
                                    __FUNCTION__,
                                    cpssp->NAME.msg_buf[0],
                                    cpssp->NAME.msg_buf[1],
                                    cpssp->NAME.msg_buf[2]);
                  }
            } while (cpssp->NAME.state_atn);

            if (skip_remaining == 1) {
                  skip_remaining = 0;
                  continue;
            }

            /* Command Phase */
            NAME_(phase_cmd)(cpssp);
            NAME_(_recv)(cpssp, 1);
            cpssp->NAME.cmd_buf[0] = cpssp->NAME.buf[0];
            switch (cpssp->NAME.cmd_buf[0]) {
            case 0x00 ... 0x1f: /* Group 0: 6 Bytes Command */
                  NAME_(_recv)(cpssp, 6 - 1);
                  memcpy(&cpssp->NAME.cmd_buf[1], cpssp->NAME.buf, 6 - 1);
                  break;
            case 0x20 ... 0x3f: /* Group 1: 10 Bytes Command */
                  NAME_(_recv)(cpssp, 10 - 1);
                  memcpy(&cpssp->NAME.cmd_buf[1], cpssp->NAME.buf, 10 - 1);
                  break;
            case 0x40 ... 0x5f: /* Group 2: 10 Bytes Command */
                  NAME_(_recv)(cpssp, 10 - 1);
                  memcpy(&cpssp->NAME.cmd_buf[1], cpssp->NAME.buf, 10 - 1);
                  break;
            case 0x80 ... 0x9f: /* Group 4: 16 Bytes Command */
                  NAME_(_recv)(cpssp, 16 - 1);
                  memcpy(&cpssp->NAME.cmd_buf[1], cpssp->NAME.buf, 16 - 1);
                  break;
            case 0xa0 ... 0xbf: /* Group 5: 12-bytes-cmd */
                  NAME_(_recv)(cpssp, 12 - 1);
                  memcpy(&cpssp->NAME.cmd_buf[1], cpssp->NAME.buf, 12 - 1);
                  break;
            default:
                  /* FIXME there could be vendor specific commands */
                  fprintf(stderr, "%s: command 0x%02x unknown.\n",
                              __FUNCTION__,
                              cpssp->NAME.cmd_buf[0]);
            }

            /* Execute Command */
            NAME_(cmd)(cpssp);

            /* Status Phase */
            NAME_(phase_status)(cpssp);
            if ( cpssp->NAME.sense_key == 0 ) {
                  cpssp->NAME.buf[0] = 0;
            } else {
                  cpssp->NAME.buf[0] = 2;
            }
            NAME_(_send)(cpssp, 1);

            NAME_(phase_msg_in)(cpssp);
            switch (cpssp->NAME.cmd_buf[0]) {
            /* any not implemented command should go here */
            case 0xa0: /* REPORT_LUNS */
                  /* reject command */
                  /* FIXME should be 0x07 (waiting for helmi) */
                  cpssp->NAME.buf[0] = 0x00;
                  break;
            default: /* Completion Byte */
                  /* send 0 here, because command completed and status sent */
                  cpssp->NAME.buf[0] = 0x00;
            }
            NAME_(_send)(cpssp, 1);
      }
}

static void
NAME_(init)(struct cpssp *cpssp)
{
      cpssp->NAME.selected = false;

      storage_init(&cpssp->NAME.media);
      storage_open(&cpssp->NAME.media, 1);

      sched_process_init(&cpssp->NAME.process, NAME_(process), cpssp);
}

static void
NAME_(create)(
      struct cpssp *cpssp,
      const char *path,
      unsigned int scsi_id,
      unsigned long size_mb
)
{
      /* Get Config */
      cpssp->NAME.scsi_id = scsi_id;

      /* get disk parameters */
      cpssp->NAME.media_blocks = (uint64_t) size_mb * 1024 * 1024 / BLOCKSIZE;
      cpssp->NAME.media.cow = 0;

      storage_create(&cpssp->NAME.media,
                  path,
                  1,      /* writable */
                  "", /* media_image */
                  size_mb,
                  BLOCKSIZE,    /* blocksize */
                  0, /* create */
                  0, /* cow */
                  0, /* sync */
                  0); /* sparse */
}

static void
NAME_(destroy)(struct cpssp *cpssp)
{
}

#endif /* BEHAVIOR */

Generated by  Doxygen 1.6.0   Back to index