libata-scsi.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,571 行 · 第 1/3 页
C
1,571 行
/* libata-scsi.c - helper library for ATA Copyright 2003-2004 Red Hat, Inc. All rights reserved. Copyright 2003-2004 Jeff Garzik The contents of this file are subject to the Open Software License version 1.1 that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is included herein by reference. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL") as distributed in the kernel source COPYING file, in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the OSL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the OSL or the GPL. */#include <linux/kernel.h>#include <linux/blkdev.h>#include <linux/spinlock.h>#include <scsi/scsi.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <linux/libata.h>#include <asm/uaccess.h>#include "libata.h"typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd);static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));static struct ata_device *ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev);/** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined * @bdev: block device associated with @sdev * @capacity: capacity of SCSI device * @geom: location to which geometry will be output * * Generic bios head/sector/cylinder calculator * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) * mapping. Some situations may arise where the disk is not * bootable if this is not used. * * LOCKING: * Defined by the SCSI layer. We don't really care. * * RETURNS: * Zero. */int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]){ geom[0] = 255; geom[1] = 63; sector_div(capacity, 255*63); geom[2] = capacity; return 0;}int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg){ struct ata_port *ap; struct ata_device *dev; int val = -EINVAL, rc = -EINVAL; ap = (struct ata_port *) &scsidev->host->hostdata[0]; if (!ap) goto out; dev = ata_scsi_find_dev(ap, scsidev); if (!dev) { rc = -ENODEV; goto out; } switch (cmd) { case ATA_IOC_GET_IO32: val = 0; if (copy_to_user(arg, &val, 1)) return -EFAULT; return 0; case ATA_IOC_SET_IO32: val = (unsigned long) arg; if (val != 0) return -EINVAL; return 0; default: rc = -EOPNOTSUPP; break; }out: return rc;}/** * ata_scsi_qc_new - acquire new ata_queued_cmd reference * @ap: ATA port to which the new command is attached * @dev: ATA device to which the new command is attached * @cmd: SCSI command that originated this ATA command * @done: SCSI command completion function * * Obtain a reference to an unused ata_queued_cmd structure, * which is the basic libata structure representing a single * ATA command sent to the hardware. * * If a command was available, fill in the SCSI-specific * portions of the structure with information on the * current command. * * LOCKING: * spin_lock_irqsave(host_set lock) * * RETURNS: * Command allocated, or %NULL if none available. */struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){ struct ata_queued_cmd *qc; qc = ata_qc_new_init(ap, dev); if (qc) { qc->scsicmd = cmd; qc->scsidone = done; if (cmd->use_sg) { qc->sg = (struct scatterlist *) cmd->request_buffer; qc->n_elem = cmd->use_sg; } else { qc->sg = &qc->sgent; qc->n_elem = 1; } } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); } return qc;}/** * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out * * Converts an ATA error into a SCSI error. While we are at it * we decode and dump the ATA error for the user so that they * have some idea what really happened at the non make-believe * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat){ struct scsi_cmnd *cmd = qc->scsicmd; u8 err = 0; unsigned char *sb = cmd->sense_buffer; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command /* BBD|ECC|ID */ {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command /* ECC|MC|MARK */ {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error /* MC|ID|ABRT|TRK0|MARK */ {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready /* MCR|MARK */ {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready /* Bad address mark */ {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field /* TRK0 */ {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error /* Abort & !ICRC */ {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command /* Media change request */ {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline /* SRV */ {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found /* Media change */ {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline /* ECC */ {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error /* BBD - block marked bad */ {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; static unsigned char stat_table[][4] = { /* Must be first because BUSY means no other bits valid */ {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ if(drv_stat & ATA_ERR) /* Read the err bits */ err = ata_chk_err(qc->ap); /* Display the ATA level error info */ printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); if(drv_stat & 0x80) { printk("Busy "); err = 0; /* Data is not valid in this case */ } else { if(drv_stat & 0x40) printk("DriveReady "); if(drv_stat & 0x20) printk("DeviceFault "); if(drv_stat & 0x10) printk("SeekComplete "); if(drv_stat & 0x08) printk("DataRequest "); if(drv_stat & 0x04) printk("CorrectedError "); if(drv_stat & 0x02) printk("Index "); if(drv_stat & 0x01) printk("Error "); } printk("}\n"); if(err) { printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); if(err & 0x04) printk("DriveStatusError "); if(err & 0x80) { if(err & 0x04) printk("BadCRC "); else printk("Sector "); } if(err & 0x40) printk("UncorrectableError "); if(err & 0x10) printk("SectorIdNotFound "); if(err & 0x02) printk("TrackZeroNotFound "); if(err & 0x01) printk("AddrMarkNotFound "); printk("}\n"); /* Should we dump sector info here too ?? */ } /* Look for err */ while(sense_table[i][0] != 0xFF) { /* Look for best matches first */ if((sense_table[i][0] & err) == sense_table[i][0]) { sb[0] = 0x70; sb[2] = sense_table[i][1]; sb[7] = 0x0a; sb[12] = sense_table[i][2]; sb[13] = sense_table[i][3]; return; } i++; } /* No immediate match */ if(err) printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); /* Fall back to interpreting status bits */ while(stat_table[i][0] != 0xFF) { if(stat_table[i][0] & drv_stat) { sb[0] = 0x70; sb[2] = stat_table[i][1]; sb[7] = 0x0a; sb[12] = stat_table[i][2]; sb[13] = stat_table[i][3]; return; } i++; } /* No error ?? */ printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ sb[0] = 0x70; sb[2] = MEDIUM_ERROR; sb[7] = 0x0A; if (cmd->sc_data_direction == SCSI_DATA_READ) { sb[12] = 0x11; /* "unrecovered read error" */ sb[13] = 0x04; } else { sb[12] = 0x0C; /* "write error - */ sb[13] = 0x02; /* auto-reallocation failed" */ }}/** * ata_scsi_slave_config - Set SCSI device attributes * @sdev: SCSI device to examine * * This is called before we actually start reading * and writing to the device, to configure certain * SCSI mid-layer behaviors. * * LOCKING: * Defined by SCSI layer. We don't really care. */int ata_scsi_slave_config(struct scsi_device *sdev){ sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD); if (sdev->id < ATA_MAX_DEVICES) { struct ata_port *ap; struct ata_device *dev; ap = (struct ata_port *) &sdev->host->hostdata[0]; dev = &ap->device[sdev->id]; /* TODO: 1024 is an arbitrary number, not the * hardware maximum. This should be increased to * 65534 when Jens Axboe's patch for dynamically * determining max_sectors is merged. */ if ((dev->flags & ATA_DFLAG_LBA48) && ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) { sdev->host->max_sectors = 2048; blk_queue_max_sectors(sdev->request_queue, 2048); } } return 0; /* scsi layer doesn't check return value, sigh */}/** * ata_scsi_error - SCSI layer error handler callback * @host: SCSI host on which error occurred * * Handles SCSI-layer-thrown error events. * * LOCKING: * Inherited from SCSI layer (none, can sleep) * * RETURNS: * Zero. */int ata_scsi_error(struct Scsi_Host *host){ struct ata_port *ap; DPRINTK("ENTER\n"); ap = (struct ata_port *) &host->hostdata[0]; ap->ops->eng_timeout(ap); /* TODO: this is per-command; when queueing is supported * this code will either change or move to a more * appropriate place */ host->host_failed--; DPRINTK("EXIT\n"); return 0;}/** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate (ignored) * * Sets up an ATA taskfile to issue FLUSH CACHE or * FLUSH CACHE EXT. * * LOCKING: * spin_lock_irqsave(host_set lock) * * RETURNS: * Zero on success, non-zero on error. */static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd){ struct ata_taskfile *tf = &qc->tf; tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; if ((tf->flags & ATA_TFLAG_LBA48) && (ata_id_has_flush_ext(qc->dev))) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; return 0;}/** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate * * Converts SCSI VERIFY command to an ATA READ VERIFY command. * * LOCKING: * spin_lock_irqsave(host_set lock) * * RETURNS: * Zero on success, non-zero on error. */static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd){ struct ata_taskfile *tf = &qc->tf; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 dev_sectors = qc->dev->n_sectors; u64 sect = 0; u32 n_sect = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; tf->device |= ATA_LBA; if (scsicmd[0] == VERIFY) { sect |= ((u64)scsicmd[2]) << 24; sect |= ((u64)scsicmd[3]) << 16; sect |= ((u64)scsicmd[4]) << 8; sect |= ((u64)scsicmd[5]); n_sect |= ((u32)scsicmd[7]) << 8; n_sect |= ((u32)scsicmd[8]); } else if (scsicmd[0] == VERIFY_16) { sect |= ((u64)scsicmd[2]) << 56; sect |= ((u64)scsicmd[3]) << 48; sect |= ((u64)scsicmd[4]) << 40; sect |= ((u64)scsicmd[5]) << 32; sect |= ((u64)scsicmd[6]) << 24; sect |= ((u64)scsicmd[7]) << 16; sect |= ((u64)scsicmd[8]) << 8; sect |= ((u64)scsicmd[9]); n_sect |= ((u32)scsicmd[10]) << 24; n_sect |= ((u32)scsicmd[11]) << 16; n_sect |= ((u32)scsicmd[12]) << 8; n_sect |= ((u32)scsicmd[13]); } else return 1; if (!n_sect) return 1; if (sect >= dev_sectors) return 1; if ((sect + n_sect) > dev_sectors) return 1; if (lba48) { if (n_sect > (64 * 1024)) return 1; } else { if (n_sect > 256) return 1; } if (lba48) { tf->hob_nsect = (n_sect >> 8) & 0xff; tf->hob_lbah = (sect >> 40) & 0xff; tf->hob_lbam = (sect >> 32) & 0xff; tf->hob_lbal = (sect >> 24) & 0xff; } else tf->device |= (sect >> 24) & 0xf; tf->nsect = n_sect & 0xff; tf->hob_lbah = (sect >> 16) & 0xff; tf->hob_lbam = (sect >> 8) & 0xff; tf->hob_lbal = sect & 0xff; return 0;}/** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate * * Converts any of six SCSI read/write commands into the * ATA counterpart, including starting sector (LBA), * sector count, and taking into account the device's LBA48 * support. * * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and * %WRITE_16 are currently supported. * * LOCKING: * spin_lock_irqsave(host_set lock) *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?