Bug 7644

Summary: Race: host lock is not acquired before calling ql_icmd
Product: SCSI Drivers Reporter: Lin Tan (tammy000)
Component: OtherAssignee: scsi_drivers-other
Status: REJECTED INVALID    
Severity: normal CC: bunk, protasnb
Priority: P2    
Hardware: i386   
OS: Linux   
Kernel Version: 2.6.19 Subsystem:
Regression: --- Bisected commit-id:

Description Lin Tan 2006-12-06 16:11:08 UTC
The caller of ql_icmd() should hold the host lock (from the head comments of
ql_icmd() shown below). But, the lock is not acquired in function
qlogicfas408_queuecommand(). All of these code is in file
drivers/scsi/qlogicfas408.c

/*
 *      Initiate scsi command - queueing handler 
 *      caller must hold host lock
 */

static void ql_icmd(struct scsi_cmnd *cmd)
{
        struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
        int     qbase = priv->qbase;
        int     int_type = priv->int_type;
        unsigned int i;

        priv->qabort = 0;

        REG0;
        /* clearing of interrupts and the fifo is needed */

 ...

------------------------------------------------------

int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
                              void (*done) (struct scsi_cmnd *))
{
        struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
        if (scmd_id(cmd) == priv->qinitid) {
                cmd->result = DID_BAD_TARGET << 16;
                done(cmd);
                return 0;
        }

        cmd->scsi_done = done;
        /* wait for the last command's interrupt to finish */
        while (priv->qlcmd != NULL) {
                barrier();
                cpu_relax();
        }
        ql_icmd(cmd);
        return 0;
}
Comment 1 Natalie Protasevich 2008-04-12 19:55:39 UTC
We do hold the lock in generic scsi code when call queuecommand.
in scsi_dispatch_cmd:

...
        spin_lock_irqsave(host->host_lock, flags);
        scsi_cmd_get_serial(host, cmd);

        if (unlikely(host->shost_state == SHOST_DEL)) {
                cmd->result = (DID_NO_CONNECT << 16);
                scsi_done(cmd);
        } else {
                rtn = host->hostt->queuecommand(cmd, scsi_done);
        }
        spin_unlock_irqrestore(host->host_lock, flags);
...

scsi_send)eh_command:

...
        spin_lock_irqsave(shost->host_lock, flags);
        scsi_log_send(scmd);
        shost->hostt->queuecommand(scmd, scsi_eh_done);
        spin_unlock_irqrestore(shost->host_lock, flags);
...

So it looks like we are good.