cpufreq: intel_pstate: Fix fast-switch fallback path
[linux-2.6-microblaze.git] / drivers / scsi / NCR5380.c
index d654a6c..2ddbcaa 100644 (file)
 static unsigned int disconnect_mask = ~0;
 module_param(disconnect_mask, int, 0444);
 
-static int do_abort(struct Scsi_Host *);
+static int do_abort(struct Scsi_Host *, unsigned int);
 static void do_reset(struct Scsi_Host *);
 static void bus_reset_cleanup(struct Scsi_Host *);
 
@@ -197,7 +197,7 @@ static inline void set_resid_from_SCp(struct scsi_cmnd *cmd)
  * @reg2: Second 5380 register to poll
  * @bit2: Second bitmask to check
  * @val2: Second expected value
- * @wait: Time-out in jiffies
+ * @wait: Time-out in jiffies, 0 if sleeping is not allowed
  *
  * Polls the chip in a reasonably efficient manner waiting for an
  * event to occur. After a short quick poll we begin to yield the CPU
@@ -223,7 +223,7 @@ static int NCR5380_poll_politely2(struct NCR5380_hostdata *hostdata,
                cpu_relax();
        } while (n--);
 
-       if (irqs_disabled() || in_interrupt())
+       if (!wait)
                return -ETIMEDOUT;
 
        /* Repeatedly sleep for 1 ms until deadline */
@@ -486,7 +486,7 @@ static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
                        break;
                case 2:
                        shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
-                       do_abort(instance);
+                       do_abort(instance, 1);
                        break;
                case 4:
                        shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
@@ -580,11 +580,14 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
 
        cmd->result = 0;
 
-       if (!NCR5380_acquire_dma_irq(instance))
-               return SCSI_MLQUEUE_HOST_BUSY;
-
        spin_lock_irqsave(&hostdata->lock, flags);
 
+       if (!NCR5380_acquire_dma_irq(instance)) {
+               spin_unlock_irqrestore(&hostdata->lock, flags);
+
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
        /*
         * Insert the cmd into the issue queue. Note that REQUEST SENSE
         * commands are added to the head of the queue since any command will
@@ -722,7 +725,6 @@ static void NCR5380_main(struct work_struct *work)
 
                        if (!NCR5380_select(instance, cmd)) {
                                dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
-                               maybe_release_dma_irq(instance);
                        } else {
                                dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
                                         "main: select failed, returning %p to queue\n", cmd);
@@ -734,8 +736,10 @@ static void NCR5380_main(struct work_struct *work)
                        NCR5380_information_transfer(instance);
                        done = 0;
                }
-               if (!hostdata->connected)
+               if (!hostdata->connected) {
                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+                       maybe_release_dma_irq(instance);
+               }
                spin_unlock_irq(&hostdata->lock);
                if (!done)
                        cond_resched();
@@ -818,7 +822,7 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
                        if (toPIO > 0) {
                                dsprintk(NDEBUG_DMA, instance,
                                         "Doing %d byte PIO to 0x%p\n", cnt, *data);
-                               NCR5380_transfer_pio(instance, &p, &cnt, data);
+                               NCR5380_transfer_pio(instance, &p, &cnt, data, 0);
                                *count -= toPIO - cnt;
                        }
                }
@@ -1185,7 +1189,7 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
                goto out;
        }
        if (!hostdata->selecting) {
-               do_abort(instance);
+               do_abort(instance, 0);
                return false;
        }
 
@@ -1196,7 +1200,7 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        len = 1;
        data = tmp;
        phase = PHASE_MSGOUT;
-       NCR5380_transfer_pio(instance, &phase, &len, &data);
+       NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
        if (len) {
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                cmd->result = DID_ERROR << 16;
@@ -1234,7 +1238,8 @@ out:
  *
  * Inputs : instance - instance of driver, *phase - pointer to
  * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
+ * bytes to transfer, **data - pointer to data pointer,
+ * can_sleep - 1 or 0 when sleeping is permitted or not, respectively.
  *
  * Returns : -1 when different phase is entered without transferring
  * maximum number of bytes, 0 if all bytes are transferred or exit
@@ -1253,7 +1258,7 @@ out:
 
 static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                                unsigned char *phase, int *count,
-                               unsigned char **data)
+                               unsigned char **data, unsigned int can_sleep)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char p = *phase, tmp;
@@ -1274,7 +1279,8 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                 * valid
                 */
 
-               if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
+               if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+                                         HZ * can_sleep) < 0)
                        break;
 
                dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
@@ -1320,7 +1326,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                }
 
                if (NCR5380_poll_politely(hostdata,
-                                         STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+                                         STATUS_REG, SR_REQ, 0, 5 * HZ * can_sleep) < 0)
                        break;
 
                dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
@@ -1395,11 +1401,12 @@ static void do_reset(struct Scsi_Host *instance)
  * do_abort - abort the currently established nexus by going to
  * MESSAGE OUT phase and sending an ABORT message.
  * @instance: relevant scsi host instance
+ * @can_sleep: 1 or 0 when sleeping is permitted or not, respectively
  *
  * Returns 0 on success, negative error code on failure.
  */
 
-static int do_abort(struct Scsi_Host *instance)
+static int do_abort(struct Scsi_Host *instance, unsigned int can_sleep)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char *msgptr, phase, tmp;
@@ -1419,7 +1426,8 @@ static int do_abort(struct Scsi_Host *instance)
         * the target sees, so we just handshake.
         */
 
-       rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+       rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+                                  10 * HZ * can_sleep);
        if (rc < 0)
                goto out;
 
@@ -1430,7 +1438,8 @@ static int do_abort(struct Scsi_Host *instance)
        if (tmp != PHASE_MSGOUT) {
                NCR5380_write(INITIATOR_COMMAND_REG,
                              ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
-               rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 3 * HZ);
+               rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0,
+                                          3 * HZ * can_sleep);
                if (rc < 0)
                        goto out;
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1440,7 +1449,7 @@ static int do_abort(struct Scsi_Host *instance)
        msgptr = &tmp;
        len = 1;
        phase = PHASE_MSGOUT;
-       NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
+       NCR5380_transfer_pio(instance, &phase, &len, &msgptr, can_sleep);
        if (len)
                rc = -ENXIO;
 
@@ -1619,12 +1628,12 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
                         */
 
                        if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
-                                                 BASR_DRQ, BASR_DRQ, HZ) < 0) {
+                                                 BASR_DRQ, BASR_DRQ, 0) < 0) {
                                result = -1;
                                shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
                        }
                        if (NCR5380_poll_politely(hostdata, STATUS_REG,
-                                                 SR_REQ, 0, HZ) < 0) {
+                                                 SR_REQ, 0, 0) < 0) {
                                result = -1;
                                shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
                        }
@@ -1636,7 +1645,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
                         */
                        if (NCR5380_poll_politely2(hostdata,
                             BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
-                            BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) {
+                            BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0) < 0) {
                                result = -1;
                                shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
                        }
@@ -1733,7 +1742,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
 #if (NDEBUG & NDEBUG_NO_DATAOUT)
                                shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
                                sink = 1;
-                               do_abort(instance);
+                               do_abort(instance, 0);
                                cmd->result = DID_ERROR << 16;
                                complete_cmd(instance, cmd);
                                hostdata->connected = NULL;
@@ -1789,7 +1798,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                           NCR5380_PIO_CHUNK_SIZE);
                                        len = transfersize;
                                        NCR5380_transfer_pio(instance, &phase, &len,
-                                                            (unsigned char **)&cmd->SCp.ptr);
+                                                            (unsigned char **)&cmd->SCp.ptr,
+                                                            0);
                                        cmd->SCp.this_residual -= transfersize - len;
                                }
 #ifdef CONFIG_SUN3
@@ -1800,7 +1810,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                        case PHASE_MSGIN:
                                len = 1;
                                data = &tmp;
-                               NCR5380_transfer_pio(instance, &phase, &len, &data);
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
                                cmd->SCp.Message = tmp;
 
                                switch (tmp) {
@@ -1841,7 +1851,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                         */
                                        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-                                       maybe_release_dma_irq(instance);
                                        return;
                                case MESSAGE_REJECT:
                                        /* Accept message by clearing ACK */
@@ -1907,7 +1916,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        len = 2;
                                        data = extended_msg + 1;
                                        phase = PHASE_MSGIN;
-                                       NCR5380_transfer_pio(instance, &phase, &len, &data);
+                                       NCR5380_transfer_pio(instance, &phase, &len, &data, 1);
                                        dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
                                                 (int)extended_msg[1],
                                                 (int)extended_msg[2]);
@@ -1920,7 +1929,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                data = extended_msg + 3;
                                                phase = PHASE_MSGIN;
 
-                                               NCR5380_transfer_pio(instance, &phase, &len, &data);
+                                               NCR5380_transfer_pio(instance, &phase, &len, &data, 1);
                                                dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
                                                         len);
 
@@ -1967,13 +1976,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                len = 1;
                                data = &msgout;
                                hostdata->last_message = msgout;
-                               NCR5380_transfer_pio(instance, &phase, &len, &data);
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
                                if (msgout == ABORT) {
                                        hostdata->connected = NULL;
                                        hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
                                        cmd->result = DID_ERROR << 16;
                                        complete_cmd(instance, cmd);
-                                       maybe_release_dma_irq(instance);
                                        return;
                                }
                                msgout = NOP;
@@ -1986,12 +1994,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                 * PSEUDO-DMA architecture we should probably
                                 * use the dma transfer function.
                                 */
-                               NCR5380_transfer_pio(instance, &phase, &len, &data);
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
                                break;
                        case PHASE_STATIN:
                                len = 1;
                                data = &tmp;
-                               NCR5380_transfer_pio(instance, &phase, &len, &data);
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
                                cmd->SCp.Status = tmp;
                                break;
                        default:
@@ -2050,7 +2058,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
 
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
        if (NCR5380_poll_politely(hostdata,
-                                 STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+                                 STATUS_REG, SR_SEL, 0, 0) < 0) {
                shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n");
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                return;
@@ -2062,12 +2070,12 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
         */
 
        if (NCR5380_poll_politely(hostdata,
-                                 STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+                                 STATUS_REG, SR_REQ, SR_REQ, 0) < 0) {
                if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0)
                        /* BUS FREE phase */
                        return;
                shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n");
-               do_abort(instance);
+               do_abort(instance, 0);
                return;
        }
 
@@ -2083,10 +2091,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                unsigned char *data = msg;
                unsigned char phase = PHASE_MSGIN;
 
-               NCR5380_transfer_pio(instance, &phase, &len, &data);
+               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
 
                if (len) {
-                       do_abort(instance);
+                       do_abort(instance, 0);
                        return;
                }
        }
@@ -2096,7 +2104,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
                spi_print_msg(msg);
                printk("\n");
-               do_abort(instance);
+               do_abort(instance, 0);
                return;
        }
        lun = msg[0] & 0x07;
@@ -2136,7 +2144,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                 * Since we have an established nexus that we can't do anything
                 * with, we must abort it.
                 */
-               if (do_abort(instance) == 0)
+               if (do_abort(instance, 0) == 0)
                        hostdata->busy[target] &= ~(1 << lun);
                return;
        }
@@ -2283,7 +2291,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
                dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
                hostdata->connected = NULL;
                hostdata->dma_len = 0;
-               if (do_abort(instance) < 0) {
+               if (do_abort(instance, 0) < 0) {
                        set_host_byte(cmd, DID_ERROR);
                        complete_cmd(instance, cmd);
                        result = FAILED;
@@ -2309,7 +2317,6 @@ out:
        }
 
        queue_work(hostdata->work_q, &hostdata->main_task);
-       maybe_release_dma_irq(instance);
        spin_unlock_irqrestore(&hostdata->lock, flags);
 
        return result;
@@ -2365,7 +2372,6 @@ static void bus_reset_cleanup(struct Scsi_Host *instance)
        hostdata->dma_len = 0;
 
        queue_work(hostdata->work_q, &hostdata->main_task);
-       maybe_release_dma_irq(instance);
 }
 
 /**