Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/**** vi:set ts=8 sts=8 sw=8:************************************************
 *
 * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 */


#include <linux/types.h>
#include <asm/byteorder.h>

/*
 * With each packet command, we allocate a buffer.
 * This is used for several packet
 * commands (Not for READ/WRITE commands).
 */

#define IDEFLOPPY_PC_BUFFER_SIZE        256
#define IDETAPE_PC_BUFFER_SIZE          256

/*
 * Packet flags bits.
 */


#define PC_ABORT                0       /* set when an error is considered normal - we won't retry */
#define PC_WAIT_FOR_DSC         1       /* 1 when polling for DSC on a media access command */
#define PC_DMA_RECOMMENDED      2       /* 1 when we prefer to use DMA if possible */
#define PC_DMA_IN_PROGRESS      3       /* 1 while DMA in progress */
#define PC_DMA_ERROR            4       /* 1 when encountered problem during DMA */
#define PC_WRITING              5       /* data direction */
#define PC_SUPPRESS_ERROR       6       /* suppress error reporting */
#define PC_TRANSFORM            7       /* transform SCSI commands */

/* This struct get's shared between different drivers.
 */

struct atapi_packet_command {
        u8 c[12];                       /* Actual packet bytes */
        char *buffer;                   /* Data buffer */
        int buffer_size;                /* Size of our data buffer */
        char *current_position;         /* Pointer into the above buffer */
        int request_transfer;           /* Bytes to transfer */
        int actually_transferred;       /* Bytes actually transferred */

        unsigned long flags;            /* Status/Action bit flags: long for set_bit */

        /* FIXME: the following is ugly as hell, but the only way we can start
         * actually to unify the code.
         */

        /* driver specific data. */
        /* floppy/tape */
        int retries;                            /* On each retry, we increment retries */
        int error;                              /* Error code */
        char *b_data;                           /* Pointer which runs on the buffers */
        unsigned int b_count;                   /* Missing/Available data on the current buffer */
        u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE]; /* Temporary buffer */
        /* Called when this packet command is completed */
        void (*callback) (struct ata_device *, struct request *);

        /* only tape */
        struct bio *bio;

        /* only scsi */
        struct {
                unsigned int b_count;                   /* Bytes transferred from current entry */
                struct scatterlist *sg;                 /* Scatter gather table */
                struct scsi_cmnd *scsi_cmd;             /* SCSI command */
                void (*done)(struct scsi_cmnd *);       /* Scsi completion routine */
                unsigned long timeout;                  /* Command timeout */
        } s;
};

/*
 *      ATAPI Status Register.
 */

typedef union {
        u8 all                  : 8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 check        : 1;    /* Error occurred */
                u8 idx          : 1;    /* Reserved */
                u8 corr         : 1;    /* Correctable error occurred */
                u8 drq          : 1;    /* Data is request by the device */
                u8 dsc          : 1;    /* Media access command finished / Buffer availability */
                u8 reserved5    : 1;    /* Reserved */
                u8 drdy         : 1;    /* Ignored for ATAPI commands (ready to accept ATA command) */
                u8 bsy          : 1;    /* The device has access to the command block */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 bsy          : 1;
                u8 drdy         : 1;
                u8 reserved5    : 1;
                u8 dsc          : 1;
                u8 drq          : 1;
                u8 corr         : 1;
                u8 idx          : 1;
                u8 check        : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_status_reg_t;

/*
 *      ATAPI error register.
 */

typedef union {
        u8 all                  : 8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 ili          : 1;    /* Illegal Length Indication */
                u8 eom          : 1;    /* End Of Media Detected */
                u8 abrt         : 1;    /* Aborted command - As defined by ATA */
                u8 mcr          : 1;    /* Media Change Requested - As defined by ATA */
                u8 sense_key    : 4;    /* Sense key of the last failed packet command */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 sense_key    : 4;
                u8 mcr          : 1;
                u8 abrt         : 1;
                u8 eom          : 1;
                u8 ili          : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_error_reg_t;

/* Currently unused, but please do not remove.  --bkz */
/*
 *      ATAPI Feature Register.
 */

typedef union {
        u8 all                  : 8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 dma          : 1;    /* Using DMA or PIO */
                u8 reserved321  : 3;    /* Reserved */
                u8 reserved654  : 3;    /* Reserved (Tag Type) */
                u8 reserved7    : 1;    /* Reserved */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 reserved7    : 1;
                u8 reserved654  : 3;
                u8 reserved321  : 3;
                u8 dma          : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_feature_reg_t;

/*
 *      ATAPI Byte Count Register.
 */

typedef union {
        u16 all                 : 16;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 low;                 /* LSB */
                u8 high;                /* MSB */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 high;
                u8 low;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_bcount_reg_t;

/*
 *      ATAPI Interrupt Reason Register.
 */

typedef union {
        u8 all                  : 8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 cod          : 1;    /* Information transferred is command (1) or data (0) */
                u8 io           : 1;    /* The device requests us to read (1) or write (0) */
                u8 reserved     : 6;    /* Reserved */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 reserved     : 6;
                u8 io           : 1;
                u8 cod          : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_ireason_reg_t;

/* Currently unused, but please do not remove.  --bkz */
/*
 *      ATAPI Drive Select Register.
 */

typedef union {
        u8 all                  :8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 sam_lun      :3;     /* Logical unit number */
                u8 reserved3    :1;     /* Reserved */
                u8 drv          :1;     /* The responding drive will be drive 0 (0) or drive 1 (1) */
                u8 one5         :1;     /* Should be set to 1 */
                u8 reserved6    :1;     /* Reserved */
                u8 one7         :1;     /* Should be set to 1 */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 one7         :1;
                u8 reserved6    :1;
                u8 one5         :1;
                u8 drv          :1;
                u8 reserved3    :1;
                u8 sam_lun      :3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_drivesel_reg_t;

/* Currently unused, but please do not remove.  --bkz */
/*
 *      ATAPI Device Control Register.
 */

typedef union {
        u8 all                  : 8;
        struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
                u8 zero0        : 1;    /* Should be set to zero */
                u8 nien         : 1;    /* Device interrupt is disabled (1) or enabled (0) */
                u8 srst         : 1;    /* ATA software reset. ATAPI devices should use the new ATAPI srst. */
                u8 one3         : 1;    /* Should be set to 1 */
                u8 reserved4567 : 4;    /* Reserved */
#elif defined(__BIG_ENDIAN_BITFIELD)
                u8 reserved4567 : 4;
                u8 one3         : 1;
                u8 srst         : 1;
                u8 nien         : 1;
                u8 zero0        : 1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        } b;
} atapi_control_reg_t;

/*
 *      The following is used to format the general configuration word
 *      of the ATAPI IDENTIFY DEVICE command.
 */

struct atapi_id_gcw {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        u8 packet_size          : 2;    /* Packet Size */
        u8 reserved234          : 3;    /* Reserved */
        u8 drq_type             : 2;    /* Command packet DRQ type */
        u8 removable            : 1;    /* Removable media */
        u8 device_type          : 5;    /* Device type */
        u8 reserved13           : 1;    /* Reserved */
        u8 protocol             : 2;    /* Protocol type */
#elif defined(__BIG_ENDIAN_BITFIELD)
        u8 protocol             : 2;
        u8 reserved13           : 1;
        u8 device_type          : 5;
        u8 removable            : 1;
        u8 drq_type             : 2;
        u8 reserved234          : 3;
        u8 packet_size          : 2;
#else
#error "Please fix <asm/byteorder.h>"
#endif
};

/*
 *      INQUIRY packet command - Data Format.
 */

typedef struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        u8      device_type     : 5;    /* Peripheral Device Type */
        u8      reserved0_765   : 3;    /* Peripheral Qualifier - Reserved */
        u8      reserved1_6t0   : 7;    /* Reserved */
        u8      rmb             : 1;    /* Removable Medium Bit */
        u8      ansi_version    : 3;    /* ANSI Version */
        u8      ecma_version    : 3;    /* ECMA Version */
        u8      iso_version     : 2;    /* ISO Version */
        u8      response_format : 4;    /* Response Data Format */
        u8      reserved3_45    : 2;    /* Reserved */
        u8      reserved3_6     : 1;    /* TrmIOP - Reserved */
        u8      reserved3_7     : 1;    /* AENC - Reserved */
#elif defined(__BIG_ENDIAN_BITFIELD)
        u8      reserved0_765   : 3;
        u8      device_type     : 5;
        u8      rmb             : 1;
        u8      reserved1_6t0   : 7;
        u8      iso_version     : 2;
        u8      ecma_version    : 3;
        u8      ansi_version    : 3;
        u8      reserved3_7     : 1;
        u8      reserved3_6     : 1;
        u8      reserved3_45    : 2;
        u8      response_format : 4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        u8      additional_length;      /* Additional Length (total_length-4) */
        u8      rsv5, rsv6, rsv7;       /* Reserved */
        u8      vendor_id[8];           /* Vendor Identification */
        u8      product_id[16];         /* Product Identification */
        u8      revision_level[4];      /* Revision Level */
        u8      vendor_specific[20];    /* Vendor Specific - Optional */
        u8      reserved56t95[40];      /* Reserved - Optional */
                                        /* Additional information may be returned */
} atapi_inquiry_result_t;

/*
 *      REQUEST SENSE packet command result - Data Format.
 */

typedef struct atapi_request_sense {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        u8      error_code      : 7;    /* Error Code (0x70 - current or 0x71 - deferred) */
        u8      valid           : 1;    /* The information field conforms to standard */
        u8      reserved1       : 8;    /* Reserved (Segment Number) */
        u8      sense_key       : 4;    /* Sense Key */
        u8      reserved2_4     : 1;    /* Reserved */
        u8      ili             : 1;    /* Incorrect Length Indicator */
        u8      eom             : 1;    /* End Of Medium */
        u8      filemark        : 1;    /* Filemark */
#elif defined(__BIG_ENDIAN_BITFIELD)
        u8      valid           : 1;
        u8      error_code      : 7;
        u8      reserved1       : 8;
        u8      filemark        : 1;
        u8      eom             : 1;
        u8      ili             : 1;
        u8      reserved2_4     : 1;
        u8      sense_key       : 4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
        u32     information __attribute__ ((packed));
        u8      asl;                    /* Additional sense length (n-7) */
        u32     command_specific;       /* Additional command specific information */
        u8      asc;                    /* Additional Sense Code */
        u8      ascq;                   /* Additional Sense Code Qualifier */
        u8      replaceable_unit_code;  /* Field Replaceable Unit Code */
#if defined(__LITTLE_ENDIAN_BITFIELD)
        u8      sk_specific1    : 7;    /* Sense Key Specific */
        u8      sksv            : 1;    /* Sense Key Specific information is valid */
#elif defined(__BIG_ENDIAN_BITFIELD)
        u8      sksv            : 1;    /* Sense Key Specific information is valid */
        u8      sk_specific1    : 7;    /* Sense Key Specific */
#else
#error "Please fix <asm/byteorder.h>"
#endif
        u8      sk_specific[2];         /* Sense Key Specific */
        u8      pad[2];                 /* Padding to 20 bytes */
} atapi_request_sense_result_t;


extern void atapi_init_pc(struct atapi_packet_command *pc);

extern void atapi_discard_data(struct ata_device *, unsigned int);
extern void atapi_write_zeros(struct ata_device *, unsigned int);

extern void atapi_read(struct ata_device *, u8 *, unsigned int);
extern void atapi_write(struct ata_device *, u8 *, unsigned int);

typedef enum {
        ide_wait,       /* insert rq at end of list, and wait for it */
        ide_preempt,    /* insert rq in front of current request */
        ide_end         /* insert rq at end of list, but don't wait for it */
} ide_action_t;

extern int ide_do_drive_cmd(struct ata_device *, struct request *, ide_action_t);