linux.oreilly.com -- An Introduction to SCSI Drivers

Figure 1: The myscsi_detect Function

int myscsi_detect(Scsi_Host_Template *tpnt)
{
      struct Scsi_Host *shpnt;
      int io = 0x320, irq = 11;	/* Assume fixed for example */
      if(myscsi_probe(io, irq) == 0)
      {
             /* Found - create an instance of this controller */
             shpnt = scsi_register(tpnt, 0);
             if(shpnt == NULL)
                   return 0;
             shpnt-›unique_id = io;
             shpnt-›io_port = io;
             shpnt-›n_io_port = MY_PORT_RANGE;
             shpnt-›irq = irq;
             shpnt-›this_id = MY_SCSI_ID;
             my_hardware_init(shpnt);
             if(request_irq(irq, my_irq_handler, 0, "myscsi", shpnt))
             {
                    scsi_unregister(shpnt);
                    printk("my_scsi: IRQ %d is busy.\n", irq);
                    return 0;
             }
      }
      return 1;
}





Figure 2: The myscsi_queuecommand Function

int myscsi_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
      int io, i;
      unsigned long flags;
      io = SCpnt-›host-›io_port;      /* Dig out our I/O port */
      current_command = SCpnt;
      current_command-›scsi_done = done;
      current_command-›SCp.Status = 0;
      save_flags(flags);
      cli();
      outb(SCpnt-›target, io + TARGET_PORT);
      for(i = 0;i ‹ SCpnt-›cmd_len;i++)
            outb(SCpnt-›cmnd[i], io + BUF + i);
      outb(COMMAND_BEGIN, io + COMMAND);
      restore_flags(flags);
      return 0;
}





Figure 3: The myscsi_abort Function

int myscsi_abort(Scsi_Cmnd *SCpnt)
{
      return SCSI_ABORT_SNOOZE;
}





Figure 4: The myscsi_reset Function

int myscsi_reset(Scsi_Cmnd *SCpnt, unsigned int flags)
{
	myhardware_reset(SCpnt-›host);
	return SCSI_RESET_PENDING;
}





Figure 5: The my_irq_handler Function

int my_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
       struct Scsi_Host *shpnt = dev_id;
       int io = shpnt-›io_port;
       u16 data;
       data = inw(io + READ_STATUS);
       if(data & RESET_DONE)
       {
              current_command-›result = DID_RESET ‹‹ 16;
              current_command-›scsi_done(current_command);
              return;
       }
       if(data & PARITY_ERROR)
       {
              current_command-›result = DID_PARITY ‹‹ 16;
              current_command-›scsi_done(current_command);
              return;
       }
       if(data & GENERAL_ERROR)
       {
              current_command-›result = DID_ERROR ‹‹ 16;
              current_command-›scsi_done(current_command);
              return;
       }
       if(data & DATA_OUT)
       {
              outsw(port + DATA_FIFO,
                     current_command-›request_buffer,
                     current_command-›request_bufflen);
       }

       if(data & DATA_IN)
       {
              int len = inw(port + DATA_LEN);
              if(len › current_command-›request_bufflen)
                     len = current_command-›request_bufflen;
              insw(port + DATA_FIFO, current_command-›request_buffer,
                            current_command-›request_bufflen);
       }
       if(data & COMMAND_DONE)
       {
              current_command-›status = inb(port + CMD_STATUS);
              current_command-›scsi_done(current_command);
       }
}





Figure 6: The myscsi_command Function

static void it_finished(Scsi_Cmnd *SCpnt)
{
      SCpnt-›SCp.Status++;
}
int myscsi_command(Scsi_Cmnd *SCpnt)
{
      myscsi_queuecommand(SCpnt, it_finished);
      /* Wait for the command to complete */
      while(!SCpnt-›SCp.Status)
            barrier();
      return SCpnt-›result;
}





Figure 7: The myscsi_info Function

const char *myscsi_info(struct Scsi_Host *SChost)
{
       return("My SCSI device");
}





Figure 8: The sym53c416_bios_param Function

int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
{
       int size;
       size = disk-›capacity;
       ip[0] = 64; /* heads */
       ip[1] = 32; /* sectors */
       if((ip[2] = size ›› 11) › 1024)
                                   /* cylinders, test for 
                                                big disk */
       {
              ip[0] = 255; /* heads */
              ip[1] = 63; /* sectors */
              ip[2] = size / (255 * 63); /* cylinders */
       }
       return 0;
}





Figure 9: The myscsi_release Function

int myscsi_release(struct Scsi_Host *SChost)
{
       free_irq(SChost-›irq, SChost);
       return 0;
}





Figure 10: The myscsi_release Function

extern int myscsi_detect(Scsi_Host_Template *);
extern const char *myscsi_info(struct Scsi_Host *)
/* ... other function definitions ... */
#define MYSCSI { \
      name:        "My SCSI Demo", \
      detect:      myscsi_detect, \
      info:        myscsi_info, \
      command:     myscsi_command, \
      queuecommand:myscsi_queuecommand, \
      abort:       myscsi_abort, \
      reset:       myscsi_reset, \
      bios_param:  myscsi_bios_param, \
      can_queue:   1, \
      this_id:     MY_SCSI_ID, \
      sg_tablesize:       SG_NONE,	\
      cmd_per_lun: 1,		\
      unchecked_isa_dma:  1,		\
      use_clustering: ENABLE_CLUSTERING, \
      proc_dir:    &myscsi_proc \
      }





Figure 11: The myscsi_proc Structure

struct proc_dir myscsi_proc =
{
       PROC_SCSI_MYSCSI, 	
       "myscsi",
       6,            /* Length of name */
       S _ IFDIR|S _ IRUGO|S _ IXUGO,
       2
};