📄 libata-scsi.c
字号:
struct scsi_cmnd *scmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; const u8 *cdb = scmd->cmnd; if (scmd->cmd_len < 5) goto invalid_fld; tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf->protocol = ATA_PROT_NODATA; if (cdb[1] & 0x1) { ; /* ignore IMMED bit, violates sat-r05 */ } if (cdb[4] & 0x2) goto invalid_fld; /* LOEJ bit set not supported */ if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) { /* the device lacks PM support, finish without doing anything */ scmd->result = SAM_STAT_GOOD; return 1; } if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ if (qc->dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; tf->lbah = 0x0; tf->lbam = 0x0; tf->lbal = 0x0; tf->device |= ATA_LBA; } else { /* CHS */ tf->lbal = 0x1; /* sect */ tf->lbam = 0x0; /* cyl low */ tf->lbah = 0x0; /* cyl high */ } tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ } else { /* XXX: This is for backward compatibility, will be * removed. Read Documentation/feature-removal-schedule.txt * for more info. */ if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) && (system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF)) { static unsigned long warned; if (!test_and_set_bit(0, &warned)) { ata_dev_printk(qc->dev, KERN_WARNING, "DISK MIGHT NOT BE SPUN DOWN PROPERLY. " "UPDATE SHUTDOWN UTILITY\n"); ata_dev_printk(qc->dev, KERN_WARNING, "For more info, visit " "http://linux-ata.org/shutdown.html\n"); /* ->scsi_done is not used, use it for * delayed completion. */ scmd->scsi_done = qc->scsidone; qc->scsidone = ata_delayed_done; } scmd->result = SAM_STAT_GOOD; return 1; } /* Issue ATA STANDBY IMMEDIATE command */ tf->command = ATA_CMD_STANDBYNOW1; } /* * Standby and Idle condition timers could be implemented but that * would require libata to implement the Power condition mode page * and allow the user to change it. Changing mode pages requires * MODE SELECT to be implemented. */ return 0;invalid_fld: ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1;}/** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile * * Sets up an ATA taskfile to issue FLUSH CACHE or * FLUSH CACHE EXT. * * LOCKING: * spin_lock_irqsave(host lock) * * RETURNS: * Zero on success, non-zero on error. */static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc){ struct ata_taskfile *tf = &qc->tf; tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; if (qc->dev->flags & ATA_DFLAG_FLUSH_EXT) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; /* flush is critical for IO integrity, consider it an IO command */ qc->flags |= ATA_QCFLAG_IO; return 0;}/** * scsi_6_lba_len - Get LBA and transfer length * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 6-byte commands. * * RETURNS: * @plba: the LBA * @plen: the transfer length */static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen){ u64 lba = 0; u32 len; VPRINTK("six-byte command\n"); lba |= ((u64)(cdb[1] & 0x1f)) << 16; lba |= ((u64)cdb[2]) << 8; lba |= ((u64)cdb[3]); len = cdb[4]; *plba = lba; *plen = len;}/** * scsi_10_lba_len - Get LBA and transfer length * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 10-byte commands. * * RETURNS: * @plba: the LBA * @plen: the transfer length */static void scsi_10_lba_len(const u8 *cdb, u64 *plba, u32 *plen){ u64 lba = 0; u32 len = 0; VPRINTK("ten-byte command\n"); lba |= ((u64)cdb[2]) << 24; lba |= ((u64)cdb[3]) << 16; lba |= ((u64)cdb[4]) << 8; lba |= ((u64)cdb[5]); len |= ((u32)cdb[7]) << 8; len |= ((u32)cdb[8]); *plba = lba; *plen = len;}/** * scsi_16_lba_len - Get LBA and transfer length * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 16-byte commands. * * RETURNS: * @plba: the LBA * @plen: the transfer length */static void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen){ u64 lba = 0; u32 len = 0; VPRINTK("sixteen-byte command\n"); lba |= ((u64)cdb[2]) << 56; lba |= ((u64)cdb[3]) << 48; lba |= ((u64)cdb[4]) << 40; lba |= ((u64)cdb[5]) << 32; lba |= ((u64)cdb[6]) << 24; lba |= ((u64)cdb[7]) << 16; lba |= ((u64)cdb[8]) << 8; lba |= ((u64)cdb[9]); len |= ((u32)cdb[10]) << 24; len |= ((u32)cdb[11]) << 16; len |= ((u32)cdb[12]) << 8; len |= ((u32)cdb[13]); *plba = lba; *plen = len;}/** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile * * Converts SCSI VERIFY command to an ATA READ VERIFY command. * * LOCKING: * spin_lock_irqsave(host lock) * * RETURNS: * Zero on success, non-zero on error. */static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc){ struct scsi_cmnd *scmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; u64 dev_sectors = qc->dev->n_sectors; const u8 *cdb = scmd->cmnd; u64 block; u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; if (cdb[0] == VERIFY) { if (scmd->cmd_len < 10) goto invalid_fld; scsi_10_lba_len(cdb, &block, &n_block); } else if (cdb[0] == VERIFY_16) { if (scmd->cmd_len < 16) goto invalid_fld; scsi_16_lba_len(cdb, &block, &n_block); } else goto invalid_fld; if (!n_block) goto nothing_to_do; if (block >= dev_sectors) goto out_of_range; if ((block + n_block) > dev_sectors) goto out_of_range; if (dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; if (lba_28_ok(block, n_block)) { /* use LBA28 */ tf->command = ATA_CMD_VERIFY; tf->device |= (block >> 24) & 0xf; } else if (lba_48_ok(block, n_block)) { if (!(dev->flags & ATA_DFLAG_LBA48)) goto out_of_range; /* use LBA48 */ tf->flags |= ATA_TFLAG_LBA48; tf->command = ATA_CMD_VERIFY_EXT; tf->hob_nsect = (n_block >> 8) & 0xff; tf->hob_lbah = (block >> 40) & 0xff; tf->hob_lbam = (block >> 32) & 0xff; tf->hob_lbal = (block >> 24) & 0xff; } else /* request too large even for LBA48 */ goto out_of_range; tf->nsect = n_block & 0xff; tf->lbah = (block >> 16) & 0xff; tf->lbam = (block >> 8) & 0xff; tf->lbal = block & 0xff; tf->device |= ATA_LBA; } else { /* CHS */ u32 sect, head, cyl, track; if (!lba_28_ok(block, n_block)) goto out_of_range; /* Convert LBA to CHS */ track = (u32)block / dev->sectors; cyl = track / dev->heads; head = track % dev->heads; sect = (u32)block % dev->sectors + 1; DPRINTK("block %u track %u cyl %u head %u sect %u\n", (u32)block, track, cyl, head, sect); /* Check whether the converted CHS can fit. Cylinder: 0-65535 Head: 0-15 Sector: 1-255*/ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) goto out_of_range; tf->command = ATA_CMD_VERIFY; tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ tf->lbal = sect; tf->lbam = cyl; tf->lbah = cyl >> 8; tf->device |= head; } return 0;invalid_fld: ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1;out_of_range: ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1;nothing_to_do: scmd->result = SAM_STAT_GOOD; return 1;}/** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile * * 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 lock) * * RETURNS: * Zero on success, non-zero on error. */static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc){ struct scsi_cmnd *scmd = qc->scsicmd; const u8 *cdb = scmd->cmnd; unsigned int tf_flags = 0; u64 block; u32 n_block; int rc; if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16) tf_flags |= ATA_TFLAG_WRITE; /* Calculate the SCSI LBA, transfer length and FUA. */ switch (cdb[0]) { case READ_10: case WRITE_10: if (unlikely(scmd->cmd_len < 10)) goto invalid_fld; scsi_10_lba_len(cdb, &block, &n_block); if (unlikely(cdb[1] & (1 << 3))) tf_flags |= ATA_TFLAG_FUA; break; case READ_6: case WRITE_6: if (unlikely(scmd->cmd_len < 6)) goto invalid_fld; scsi_6_lba_len(cdb, &block, &n_block); /* for 6-byte r/w commands, transfer length 0 * means 256 blocks of data, not 0 block. */ if (!n_block) n_block = 256; break; case READ_16: case WRITE_16: if (unlikely(scmd->cmd_len < 16)) goto invalid_fld; scsi_16_lba_len(cdb, &block, &n_block); if (unlikely(cdb[1] & (1 << 3))) tf_flags |= ATA_TFLAG_FUA; break; default: DPRINTK("no-byte command\n"); goto invalid_fld; } /* Check and compose ATA command */ if (!n_block) /* For 10-byte and 16-byte SCSI R/W commands, transfer * length 0 means transfer 0 block of data. * However, for ATA R/W commands, sector count 0 means * 256 or 65536 sectors, not 0 sectors as in SCSI. * * WARNING: one or two older ATA drives treat 0 as 0... */ goto nothing_to_do; qc->flags |= ATA_QCFLAG_IO; qc->nbytes = n_block * ATA_SECT_SIZE; rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, qc->tag); if (likely(rc == 0)) return 0; if (rc == -ERANGE) goto out_of_range; /* treat all other errors as -EINVAL, fall through */invalid_fld: ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1;out_of_range: ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1;nothing_to_do: scmd->result = SAM_STAT_GOOD; return 1;}static void ata_scsi_qc_complete(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; int need_sense = (qc->err_mask != 0); /* For ATA pass thru (SAT) commands, generate a sense block if * user mandated it or if there's an error. Note that if we * generate because the user forced us to, a check condition * is generated and the ATA register values are returned * whether the command completed successfully or not. If there * was no error, SK, ASC and ASCQ will all be zero. */ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) { ata_gen_passthru_sense(qc); } else { if (!need_sense) { cmd->result = SAM_STAT_GOOD; } else { /* TODO: decide which descriptor format to use * for 48b LBA devices and call that here * instead of the fixed desc, which is only * good for smaller LBA (and maybe CHS?) * devices. */ ata_gen_ata_sense(qc); } } /* XXX: track spindown state for spindown skipping and warning */ if (unlikely(qc->tf.command == ATA_CMD_STANDBY || qc->tf.command == ATA_CMD_STANDBYNOW1)) qc->dev->flags |= ATA_DFLAG_SPUNDOWN; else if (likely(system_state != SYSTEM_HALT && system_state != SYSTEM_POWER_OFF)) qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN; if (need_sense && !ap->ops->error_handler) ata_dump_status(ap->print_id, &qc->result_tf); qc->scsidone(cmd); ata_qc_free(qc);}/** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed * @cmd: SCSI command to execute * @done: SCSI command completion function * @xlat_func: Actor which translates @cmd to an ATA taskfile * * Our ->queuecommand() function has decided that the SCSI * command issued can be directly translated into an ATA * command, rather than handled internally. * * This function sets up an ata_queued_cmd structure for the * SCSI command, and sends that ata_queued_cmd to the hardware. * * The xlat_func argument (actor) returns 0 if ready to execute * ATA command, else 1 to finish translation. If 1 is returned * then cmd->result (and possibly cmd->sense_buffer) are assumed * to be set reflecting an error condition or clean (early)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -