#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/resident.h>
#include <exec/memory.h>
#include <exec/devices.h>
#include <libraries/expansionbase.h>
#include <libraries/configvars.h>

/*
 * Set SysBase to a local variable, that loads directly from 4 when it
 * has to be reloaded
 */
#define BASE_EXT_DECL
#define BASE_NAME (*(void **)4)
#include <inline/exec.h>

#include "device.h"

/*
 * Check a given scsi unit for an attached device.
 */

extern void unit_start(struct scsi_unit *unit);
DECL_DPRINTF;

void
try_unit(struct scsi_dev *dev, int unit)
{
  /* this checks, whether an scsi-device responds to the given 
   * unit number.
   * if there is a unit responding, a unit task is created */
  ubyte cmd[12];
  struct scsi_msg *sc = &dev->sc_hmessage;
  struct SCSICmd scd;
  ulong sense_buf;
  struct scsi_unit *su;
  struct Task *tcb;
  int retries;

  dev->sc_units[unit] = 0;

#ifdef DEBUG
/*  if (unit != 2 && unit != 4) return;*/
#endif

  sc->scm_message.mn_ReplyPort = &dev->sc_msgport;
  
  /* first do a TEST UNIT READY, if there is no device of that unit
   * the answer will be a select-timeout */
   
  cmd[0] = cmd[1] = cmd[2] = cmd[3] = cmd[4] = cmd[5] = 0;
  sc->scm_scsi_cmd = &scd;
  
  scd.scsi_Length = 0;
  scd.scsi_Command = cmd;
  scd.scsi_CmdLength = 6;
  /* swallow any UNIT ATTENTION responses */
  scd.scsi_Flags = SCSIF_READ|SCSIF_OLDAUTOSENSE;
  scd.scsi_SenseData = (UBYTE *)&sense_buf;
  scd.scsi_SenseLength = 4;

  retries = 60;
  do
    {
      sc->scm_cmd = SCM_CMD_EXEC_SCSI;
      sc->scm_unit = unit;
  
      PutGetMsg(dev->sc_hmsgport, &dev->sc_msgport, (struct Message *)sc);
    }
  while ((sc->scm_cmd == HFERR_DMA || sc->scm_cmd == HFERR_Phase) && retries-- >= 0) ;

  /* in these two cases, a unit is attached to the bus, no matter
   * whether it is currently ready or not */
  if (sc->scm_cmd == 0 || sc->scm_cmd == HFERR_BadStatus)
    {
      /* now set up a task for this unit */
      
DPRINTF(("unit %ld ok, starting unit task", unit));

      su = (struct scsi_unit *)AllocMem(sizeof(*su), MEMF_CLEAR|MEMF_PUBLIC);
      dev->sc_units[unit] = su;
      
      su->scu_unitnum = unit;
      su->scu_device = dev;
      su->scu_hmsgport = dev->sc_hmsgport;
      sc = &su->scu_hmessage;
      
      tcb = &su->scu_tcb;
      tcb->tc_SPLower = (APTR)su->scu_stack;
      tcb->tc_SPUpper = (APTR)(su->scu_stack + UNIT_STACKSIZE);
      tcb->tc_SPReg = (APTR)(tcb->tc_SPUpper - 4);
      /* pass the child the unit pointer */
      *(struct scsi_unit **)tcb->tc_SPReg = su;
	
      tcb->tc_Node.ln_Type = NT_TASK;	    
      tcb->tc_Node.ln_Pri = UNIT_PRIORITY;
      tcb->tc_Node.ln_Name = UNIT_NAME;
	
      NewList(&tcb->tc_MemEntry);
	
      AddTask(tcb, unit_start, 0);

      /* the unit now figures out itself, of which type it is */
DPRINTF(("unit %ld TEST READY ok", unit));
    }
  else
DPRINTF(("unit %ld TEST READY negativ", unit));
}


