root/kernel/blk_drv/scsi/ultrastor.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ultrastor_detect
  2. ultrastor_info
  3. build_sg_list
  4. ultrastor_queuecommand
  5. ultrastor_abort
  6. ultrastor_reset
  7. ultrastor_biosparam
  8. ultrastor_interrupt

   1 /*
   2  *      ultrastor.c     Copyright (C) 1992 David B. Gentzel
   3  *      Low-level SCSI driver for UltraStor 14F
   4  *      by David B. Gentzel, Whitfield Software Services, Carnegie, PA
   5  *          (gentzel@nova.enet.dec.com)
   6  *  scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
   7  *      Thanks to UltraStor for providing the necessary documentation
   8  */
   9 
  10 /*
  11  * TODO:
  12  *      1. Cleanup error handling & reporting.
  13  *      2. Find out why scatter/gather is limited to 16 requests per command.
  14  *      3. Add multiple outstanding requests.
  15  *      4. See if we can make good use of having more than one command per lun.
  16  *      5. Test/improve/fix abort & reset functions.
  17  *      6. Look at command linking (mscp.command_link and
  18  *         mscp.command_link_id).
  19  */
  20 
  21 /*
  22  * NOTES:
  23  *    The UltraStor 14F is one of a family of intelligent, high performance
  24  *    SCSI-2 host adapters.  They all support command queueing and
  25  *    scatter/gather I/O.  Some of them can also emulate the standard
  26  *    WD1003 interface for use with OS's which don't support SCSI.
  27  *    Here is the scoop on the various models:
  28  *      14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
  29  *      14N - ISA HA with floppy support.  I think that this is a non-DMA
  30  *            HA.  Nothing further known.
  31  *      24F - EISA Bus Master HA with floppy support and WD1003 emulation.
  32  *      34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
  33  *
  34  *    The 14F is supported by this driver.  An effort has been made to support
  35  *    the 34F.  It should work, but is untested.  The 24F does not work at
  36  *    present.
  37  *
  38  *    Places flagged with a triple question-mark are things which are either
  39  *    unfinished, questionable, or wrong.
  40  */
  41 
  42 #include <linux/stddef.h>
  43 #include <linux/string.h>
  44 #include <linux/sched.h>
  45 #include <linux/kernel.h>
  46 #include <linux/ioport.h>
  47 
  48 #include <asm/io.h>
  49 #include <asm/system.h>
  50 #include <asm/dma.h>
  51 
  52 #define ULTRASTOR_PRIVATE       /* Get the private stuff from ultrastor.h */
  53 #include "../blk.h"
  54 #include "scsi.h"
  55 #include "hosts.h"
  56 #include "ultrastor.h"
  57 
  58 #define ULTRASTOR_DEBUG 0
  59 
  60 #define VERSION "1.1 alpha"
  61 
  62 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
  63 #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
  64 
  65 /* Simply using "unsigned long" in these structures won't work as it causes
  66    alignment.  Perhaps the "aligned" attribute may be used in GCC 2.0 to get
  67    around this, but for now I use this hack. */
  68 typedef struct {
  69     unsigned char bytes[4];
  70 } Longword;
  71 
  72 /* Used to fetch the configuration info from the config i/o registers.  We
  73    then store (in a friendlier format) in config. */
  74 struct config_1 {
  75     unsigned char bios_segment: 3;
  76     unsigned char removable_disks_as_fixed: 1;
  77     unsigned char interrupt: 2;
  78     unsigned char dma_channel: 2;
  79 };
  80 struct config_2 {
  81     unsigned char ha_scsi_id: 3;
  82     unsigned char mapping_mode: 2;
  83     unsigned char bios_drive_number: 1;
  84     unsigned char tfr_port: 2;
  85 };
  86 
  87 /* Used to store configuration info read from config i/o registers.  Most of
  88    this is not used yet, but might as well save it. */
  89 struct config {
  90     const void *bios_segment;
  91     unsigned short port_address;
  92     unsigned char interrupt: 4;
  93     unsigned char dma_channel: 3;
  94     unsigned char bios_drive_number: 1;
  95     unsigned char heads;
  96     unsigned char sectors;
  97     unsigned char ha_scsi_id: 3;
  98     unsigned char subversion: 4;
  99 };
 100 
 101 /* MailBox SCSI Command Packet.  Basic command structure for communicating
 102    with controller. */
 103 struct mscp {
 104     unsigned char opcode: 3;            /* type of command */
 105     unsigned char xdir: 2;              /* data transfer direction */
 106     unsigned char dcn: 1;               /* disable disconnect */
 107     unsigned char ca: 1;                /* use cache (if available) */
 108     unsigned char sg: 1;                /* scatter/gather operation */
 109     unsigned char target_id: 3;         /* target SCSI id */
 110     unsigned char ch_no: 2;             /* SCSI channel (always 0 for 14f) */
 111     unsigned char lun: 3;               /* logical unit number */
 112     Longword transfer_data;             /* transfer data pointer */
 113     Longword transfer_data_length;      /* length in bytes */
 114     Longword command_link;              /* for linking command chains */
 115     unsigned char scsi_command_link_id; /* identifies command in chain */
 116     unsigned char number_of_sg_list;    /* (if sg is set) 8 bytes per list */
 117     unsigned char length_of_sense_byte;
 118     unsigned char length_of_scsi_cdbs;  /* 6, 10, or 12 */
 119     unsigned char scsi_cdbs[12];        /* SCSI commands */
 120     unsigned char adapter_status;       /* non-zero indicates HA error */
 121     unsigned char target_status;        /* non-zero indicates target error */
 122     Longword sense_data;
 123 };
 124 
 125 /* The 14F uses an array of unaligned 4-byte ints for its scatter/gather list. */
 126 typedef struct {
 127         unsigned long address;
 128         unsigned long num_bytes;
 129 } ultrastor_sg_list;
 130 
 131 /* This is our semaphore for mscp block availability */
 132 int mscp_free = TRUE;
 133 
 134 /* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
 135 static const void *const bios_segment_table_14f[8] = {
 136     NULL,            (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
 137     (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
 138 };
 139 
 140 /* Allowed IRQs for 14f */
 141 static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 };
 142 
 143 /* Allowed DMA channels for 14f (0 indicates reserved) */
 144 static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
 145 
 146 /* Head/sector mappings allowed by 14f */
 147 static const struct {
 148     unsigned char heads;
 149     unsigned char sectors;
 150 } mapping_table_14f[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
 151 
 152 /* Subversions of the 14F */
 153 static const char *const subversion_names[] = { "14F", "34F" };
 154 
 155 /* Config info */
 156 static struct config config;
 157 
 158 /* Our index in the host adapter array maintained by higher-level driver */
 159 static int host_number;
 160 
 161 /* PORT_ADDRESS is first port address used for i/o of messages. */
 162 #ifdef PORT_OVERRIDE
 163 # define PORT_ADDRESS PORT_OVERRIDE
 164 #else
 165 # define PORT_ADDRESS (config.port_address)
 166 #endif
 167 
 168 static volatile int aborted = 0;
 169 
 170 #ifndef PORT_OVERRIDE
 171 /* ??? A probe of address 0x310 screws up NE2000 cards */
 172 static const unsigned short ultrastor_ports_14f[] = {
 173     0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
 174 };
 175 #endif
 176 
 177 static void ultrastor_interrupt(int cpl);
 178 static inline void build_sg_list(Scsi_Cmnd *SCpnt);
 179 
 180 static void (*ultrastor_done)(Scsi_Cmnd *) = 0;
 181 static Scsi_Cmnd *SCint = NULL;
 182 
 183 int ultrastor_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185     size_t i;
 186     unsigned char in_byte, version_byte = 0;
 187     struct config_1 config_1;
 188     struct config_2 config_2;
 189 
 190 #if (ULTRASTOR_DEBUG & UD_DETECT)
 191     printk("US14F: detect: called\n");
 192 #endif
 193 
 194 #ifndef PORT_OVERRIDE
 195     PORT_ADDRESS = 0;
 196     for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
 197         PORT_ADDRESS = ultrastor_ports_14f[i];
 198         if(check_region(PORT_ADDRESS, 4)) continue;
 199 #else
 200         if(check_region(PORT_ADDRESS, 4)) {
 201           printk("Ultrastor I/O space already in use\n");
 202           return FALSE;
 203         };
 204 #endif
 205 
 206 #if (ULTRASTOR_DEBUG & UD_DETECT)
 207         printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
 208 #endif
 209 
 210         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
 211         if (in_byte != US14F_PRODUCT_ID_0) {
 212 #if (ULTRASTOR_DEBUG & UD_DETECT)
 213 # ifdef PORT_OVERRIDE
 214             printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
 215 # else
 216             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 217 # endif
 218 #endif
 219 #ifdef PORT_OVERRIDE
 220             return FALSE;
 221 #else
 222             continue;
 223 #endif
 224         }
 225         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
 226         /* Only upper nibble is significant for Product ID 1 */
 227         if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
 228 #if (ULTRASTOR_DEBUG & UD_DETECT)
 229 # ifdef PORT_OVERRIDE
 230             printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
 231 # else
 232             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 233 # endif
 234 #endif
 235 #ifdef PORT_OVERRIDE
 236             return FALSE;
 237 #else
 238             continue;
 239 #endif
 240         }
 241         version_byte = in_byte;
 242 #ifndef PORT_OVERRIDE
 243         break;
 244     }
 245     if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
 246 # if (ULTRASTOR_DEBUG & UD_DETECT)
 247         printk("US14F: detect: no port address found!\n");
 248 # endif
 249         return FALSE;
 250     }
 251 #endif
 252 
 253 #if (ULTRASTOR_DEBUG & UD_DETECT)
 254     printk("US14F: detect: adapter found at port address %03X\n",
 255            PORT_ADDRESS);
 256 #endif
 257 
 258     snarf_region(PORT_ADDRESS, 4); /* Register the I/O space that we use */
 259     /* All above tests passed, must be the right thing.  Get some useful
 260        info. */
 261     *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
 262     *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
 263     config.bios_segment = bios_segment_table_14f[config_1.bios_segment];
 264     config.interrupt = interrupt_table_14f[config_1.interrupt];
 265     config.ha_scsi_id = config_2.ha_scsi_id;
 266     config.heads = mapping_table_14f[config_2.mapping_mode].heads;
 267     config.sectors = mapping_table_14f[config_2.mapping_mode].sectors;
 268     config.bios_drive_number = config_2.bios_drive_number;
 269     config.subversion = (version_byte & 0x0F);
 270     if (config.subversion == U34F)
 271         config.dma_channel = 0;
 272     else
 273         config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
 274 
 275     if (!config.bios_segment) {
 276 #if (ULTRASTOR_DEBUG & UD_DETECT)
 277         printk("US14F: detect: not detected.\n");
 278 #endif
 279         return FALSE;
 280     }
 281 
 282     /* Final consistancy check, verify previous info. */
 283     if (config.subversion != U34F)
 284         if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
 285 #if (ULTRASTOR_DEBUG & UD_DETECT)
 286             printk("US14F: detect: consistancy check failed\n");
 287 #endif
 288             return FALSE;
 289         }
 290 
 291     /* If we were TRULY paranoid, we could issue a host adapter inquiry
 292        command here and verify the data returned.  But frankly, I'm
 293        exhausted! */
 294 
 295     /* Finally!  Now I'm satisfied... */
 296 #if (ULTRASTOR_DEBUG & UD_DETECT)
 297     printk("US14F: detect: detect succeeded\n"
 298            "  Port address: %03X\n"
 299            "  BIOS segment: %05X\n"
 300            "  Interrupt: %u\n"
 301            "  DMA channel: %u\n"
 302            "  H/A SCSI ID: %u\n"
 303            "  Subversion: %u\n",
 304            PORT_ADDRESS, config.bios_segment, config.interrupt,
 305            config.dma_channel, config.ha_scsi_id, config.subversion);
 306 #endif
 307     host_number = hostnum;
 308     scsi_hosts[hostnum].this_id = config.ha_scsi_id;
 309     scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);
 310 
 311     if (request_irq(config.interrupt, ultrastor_interrupt)) {
 312         printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 313                config.interrupt);
 314         return FALSE;
 315     }
 316     if (config.dma_channel && request_dma(config.dma_channel)) {
 317         printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
 318                config.dma_channel);
 319         free_irq(config.interrupt);
 320         return FALSE;
 321     }
 322         scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
 323         printk("UltraStor: scatter/gather enabled.  Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG);
 324 
 325     return TRUE;
 326 }
 327 
 328 const char *ultrastor_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330     static char buf[64];
 331 
 332     (void)sprintf(buf, "UltraStor %s SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
 333                   ((config.subversion < ARRAY_SIZE(subversion_names))
 334                    ? subversion_names[config.subversion] : "14F?"),
 335                   PORT_ADDRESS, (int)config.bios_segment, config.interrupt,
 336                   config.dma_channel);
 337     return buf;
 338 }
 339 
 340 static struct mscp mscp = {
 341     OP_SCSI, DTD_SCSI, 0, 1, 0          /* This stuff doesn't change */
 342 };
 343 
 344 static inline void build_sg_list(Scsi_Cmnd *SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346         ultrastor_sg_list *sglist;
 347         struct scatterlist *sl;
 348         long transfer_length = 0;
 349         int i;
 350 
 351         sl = (struct scatterlist *) SCpnt->request_buffer;
 352         SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
 353         if (SCpnt->host_scribble == NULL)
 354                 /* Not sure what to do here; just panic for now */
 355                 panic("US14F: Can't allocate DMA buffer for scatter-gather list!\n");
 356         /* Save ourselves some casts; can eliminate when we don't have to look at it anymore! */
 357         sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
 358         for (i = 0; i < SCpnt->use_sg; i++) {
 359                 sglist[i].address = (unsigned long) sl[i].address;
 360                 sglist[i].num_bytes = sl[i].length;
 361                 transfer_length += sl[i].length;
 362         }
 363         mscp.number_of_sg_list = (char) SCpnt->use_sg;
 364         mscp.transfer_data = *(Longword *)&sglist;
 365         /* ??? May not be necessary.  Docs are unclear as to whether transfer length field is */
 366         /* ignored or whether it should be set to the total number of bytes of the transfer.  */
 367         mscp.transfer_data_length = *(Longword *)&transfer_length;
 368 }
 369 
 370 int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372     unsigned char in_byte;
 373 
 374 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 375     printk("US14F: queuecommand: called\n");
 376 #endif
 377 
 378         /* We want to be sure that a command queued while another command   */
 379         /* is running doesn't overwrite the mscp block until the running    */
 380         /* command is finished.  mscp_free is set in the interrupt handler. */
 381         /* I'm not sure if the upper level driver will send another command */
 382         /* with a command pending; this is just insurance.                  */
 383         while (1) {
 384                 cli();
 385                 if (mscp_free) {
 386                         mscp_free = FALSE;
 387                         sti();
 388                         break;
 389                 }
 390                 sti();
 391         }
 392     mscp.opcode = OP_SCSI;
 393     mscp.xdir = DTD_SCSI;
 394     mscp.dcn = FALSE;
 395     /* Tape drives don't work properly if the cache is used.  The SCSI
 396        READ command for a tape doesn't have a block offset, and the adapter
 397        incorrectly assumes that all reads from the tape read the same
 398        blocks.  Results will depend on read buffer size and other disk
 399        activity. 
 400 
 401        ???  Which other device types should never use the cache?   */
 402     mscp.ca = scsi_devices[SCpnt->index].type != TYPE_TAPE;
 403     mscp.target_id = SCpnt->target;
 404     mscp.ch_no = 0;
 405     mscp.lun = SCpnt->lun;
 406         if (SCpnt->use_sg) {
 407                 /* Set scatter/gather flag in SCSI command packet */
 408                 mscp.sg = TRUE;
 409                 build_sg_list(SCpnt);
 410         }
 411         else {
 412                 /* Unset scatter/gather flag in SCSI command packet */
 413                 mscp.sg = FALSE;
 414                 mscp.transfer_data = *(Longword *)&SCpnt->request_buffer;
 415                 mscp.transfer_data_length = *(Longword *)&SCpnt->request_bufflen;
 416                 SCpnt->host_scribble = NULL;
 417         }
 418     memset(&mscp.command_link, 0, sizeof(mscp.command_link));   /*???*/
 419     mscp.scsi_command_link_id = 0;      /*???*/
 420     mscp.length_of_sense_byte = 0;      /*???*/
 421     mscp.length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
 422     memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
 423     mscp.adapter_status = 0;
 424     mscp.target_status = 0;
 425     memset(&mscp.sense_data, 0, sizeof(mscp.sense_data));       /*???*/
 426 
 427     /* Find free OGM slot (OGMINT bit is 0) */
 428     do
 429         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 430     while (!aborted && (in_byte & 1));
 431     if (aborted) {
 432 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
 433         printk("US14F: queuecommand: aborted\n");
 434 #endif
 435         /* ??? is this right? */
 436         return (aborted << 16);
 437     }
 438 
 439     /* Store pointer in OGM address bytes */
 440     outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
 441     outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
 442     outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
 443     outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
 444 
 445     /* Issue OGM interrupt */
 446     outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
 447 
 448     ultrastor_done = done;
 449     SCint = SCpnt;
 450 
 451 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 452     printk("US14F: queuecommand: returning\n");
 453 #endif
 454 
 455     return 0;
 456 }
 457 
 458 int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 459 {
 460 #if (ULTRASTOR_DEBUG & UD_ABORT)
 461     printk("US14F: abort: called\n");
 462 #endif
 463 
 464     aborted = (code ? code : DID_ABORT);
 465 
 466         /* Free DMA buffer used for scatter/gather list */
 467         if (SCpnt->host_scribble)
 468                 scsi_free(SCpnt->host_scribble, 512);
 469 
 470         /* Free up mscp block for next command */
 471         mscp_free = TRUE;
 472 
 473 #if (ULTRASTOR_DEBUG & UD_ABORT)
 474     printk("US14F: abort: returning\n");
 475 #endif
 476 
 477     return 0;
 478 }
 479 
 480 int ultrastor_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 481 {
 482 #if 0
 483     unsigned char in_byte;
 484 #endif
 485 
 486 #if (ULTRASTOR_DEBUG & UD_RESET)
 487     printk("US14F: reset: called\n");
 488 #endif
 489 
 490         /* ??? SCSI bus reset causes problems on some systems. */
 491 #if 0
 492     /* Issue SCSI BUS reset */
 493     outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
 494 
 495     /* Wait for completion... */
 496     do
 497         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 498     while (in_byte & 0x20);
 499 
 500     aborted = DID_RESET;
 501 #endif
 502 
 503 #if (ULTRASTOR_DEBUG & UD_RESET)
 504     printk("US14F: reset: returning\n");
 505 #endif
 506     return 0;
 507 }
 508 
 509 int ultrastor_biosparam(int size, int dev, int *ip)
     /* [previous][next][first][last][top][bottom][index][help] */
 510 {
 511     unsigned int s = config.heads * config.sectors;
 512 
 513     ip[0] = config.heads;
 514     ip[1] = config.sectors;
 515     ip[2] = (size + (s - 1)) / s;
 516 /*    if (ip[2] > 1024)
 517         ip[2] = 1024; */
 518     return 0;
 519 }
 520 
 521 static void ultrastor_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 524     printk("US14F: interrupt: called: status = %08X\n",
 525            (mscp.adapter_status << 16) | mscp.target_status);
 526 #endif
 527 
 528     if (ultrastor_done == 0)
 529         panic("US14F: interrupt: unexpected interrupt");
 530     else {
 531         void (*done)(Scsi_Cmnd *);
 532         Scsi_Cmnd *SCtmp;
 533 
 534         /* Save ultrastor_done locally and zero before calling.  This is needed
 535            as once we call done, we may get another command queued before this
 536            interrupt service routine can return. */
 537         done = ultrastor_done;
 538         ultrastor_done = 0;
 539         SCtmp = SCint;
 540 
 541         /* Clean ICM slot (set ICMINT bit to 0) */
 542         outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
 543 
 544         /* Let the higher levels know that we're done */
 545         /* ??? status is wrong here... */
 546         SCtmp->result = (mscp.adapter_status << 16) | mscp.target_status;
 547 
 548         /* Free temp space used for scatter-gather list */
 549         if (SCtmp->host_scribble)
 550                 scsi_free(SCtmp->host_scribble, 512);
 551 
 552         /* Free up mscp block for next command */
 553         mscp_free = TRUE;
 554 
 555         done(SCtmp);
 556     }
 557 
 558 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 559     printk("US14F: interrupt: returning\n");
 560 #endif
 561 }

/* [previous][next][first][last][top][bottom][index][help] */