Hello, This patch is a port of Hannes Reinecke "qfrozen to atomic_t" patch to aic7xxx. It's a naive "copy and paste" patch but there is differences in ahc_linux_run_command. ahc_linux_run_command seems to do nasty tests with the qfrozen counter and the tagged or untagged command case, but it is out of my competence. This patch is diffed on top of the latest Christoph Hellwig "semaphore to completion conversion". Compiled, will be tested this evening. I just saw your conversation with Christoph. If you want I try another version, tell me. Emmanuel. --- Accédez au courrier électronique de La Poste : www.laposte.net ; 3615 LAPOSTENET (0,34 ?/mn) ; tél : 08 92 68 13 50 (0,34?/mn)
Subject: [PATCH 1/1] aic7xxx: port of the "qfrozen to atomic_t" patch This patch is a port of Hannes Reinecke "qfrozen to atomic_t" patch to aic7xxx. It's a naive "copy and paste" patch but there is differences in ahc_linux_run_command. ahc_linux_run_command seems to do nasty tests with the qfrozen counter and the tagged or untagged command case, but it is out of my competence. This patch is diffed on top of the latest Christoph Hellwig "semaphore to completion conversion". Signed-off-by: Emmanuel Fusté <emmanuel.fuste@xxxxxxxxxxx> --- aic7xxx_osm.c | 57 +++++++++++++++++++-------------------------------------- aic7xxx_osm.h | 2 +- 2 files changed, 20 insertions(+), 39 deletions(-) --- linux-source-2.6.15-orig/drivers/scsi/aic7xxx/aic7xxx_osm.c 2006-02-07 10:48:30.000000000 +0100 +++ linux-source-2.6.15/drivers/scsi/aic7xxx/aic7xxx_osm.c 2006-02-07 13:50:40.000000000 +0100 @@ -476,17 +476,14 @@ ahc_linux_queue(struct scsi_cmnd * cmd, struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); int rtn = SCSI_MLQUEUE_HOST_BUSY; - unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - ahc_lock(ahc, &flags); - if (ahc->platform_data->qfrozen == 0) { + if (!atomic_read(&ahc->platform_data->qfrozen)) { cmd->scsi_done = scsi_done; cmd->result = CAM_REQ_INPROG << 16; rtn = ahc_linux_run_command(ahc, dev, cmd); } - ahc_unlock(ahc, &flags); return rtn; } @@ -747,14 +744,11 @@ ahc_linux_bus_reset(struct scsi_cmnd *cm { struct ahc_softc *ahc; int found; - unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - ahc_lock(ahc, &flags); found = ahc_reset_channel(ahc, scmd_channel(cmd) + 'A', /*initiate reset*/TRUE); - ahc_unlock(ahc, &flags); if (bootverbose) printf("%s: SCSI bus reset delivered. " @@ -1184,6 +1178,7 @@ ahc_platform_alloc(struct ahc_softc *ahc memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc_lockinit(ahc); + atomic_set(&ahc->platform_data->qfrozen, 0); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (aic7xxx_pci_parity == 0) @@ -1406,13 +1401,18 @@ ahc_linux_run_command(struct ahc_softc * struct ahc_tmode_tstate *tstate; uint16_t mask; struct scb_tailq *untagged_q = NULL; + unsigned long flags; + + ahc_lock(ahc, &flags); /* * Schedule us to run later. The only reason we are not * running is because the whole controller Q is frozen. */ - if (ahc->platform_data->qfrozen != 0) + if (atomic_read(&ahc->platform_data->qfrozen)) { + ahc_unlock(ahc, &flags); return SCSI_MLQUEUE_HOST_BUSY; + } /* * We only allow one untagged transaction @@ -1426,18 +1426,22 @@ ahc_linux_run_command(struct ahc_softc * target_offset = cmd->device->id + cmd->device->channel * 8; untagged_q = &(ahc->untagged_queues[target_offset]); - if (!TAILQ_EMPTY(untagged_q)) + if (!TAILQ_EMPTY(untagged_q)) { /* if we're already executing an untagged command * we're busy to another */ + ahc_unlock(ahc, &flags); return SCSI_MLQUEUE_DEVICE_BUSY; + } } /* * Get an scb to use. */ scb = ahc_get_scb(ahc); - if (!scb) + if (!scb) { + ahc_unlock(ahc, &flags); return SCSI_MLQUEUE_HOST_BUSY; + } scb->io_ctx = cmd; scb->platform_data->dev = dev; @@ -1588,6 +1592,9 @@ ahc_linux_run_command(struct ahc_softc * scb->flags |= SCB_UNTAGGEDQ; } ahc_queue_scb(ahc, scb); + + ahc_unlock(ahc, &flags); + return 0; } @@ -2025,41 +2032,15 @@ ahc_linux_queue_cmd_complete(struct ahc_ static void ahc_linux_freeze_simq(struct ahc_softc *ahc) { - unsigned long s; - ahc_lock(ahc, &s); - ahc->platform_data->qfrozen++; - if (ahc->platform_data->qfrozen == 1) { + if (!atomic_inc_and_test(&ahc->platform_data->qfrozen)) scsi_block_requests(ahc->platform_data->host); - - /* XXX What about Twin channels? */ - ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ); - } - ahc_unlock(ahc, &s); } static void ahc_linux_release_simq(struct ahc_softc *ahc) { - u_long s; - int unblock_reqs; - - unblock_reqs = 0; - ahc_lock(ahc, &s); - if (ahc->platform_data->qfrozen > 0) - ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - unblock_reqs = 1; - ahc_unlock(ahc, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) + if (atomic_dec_and_test(&ahc->platform_data->qfrozen)) scsi_unblock_requests(ahc->platform_data->host); } --- linux-source-2.6.15-orig/drivers/scsi/aic7xxx/aic7xxx_osm.h 2006-02-07 10:48:38.000000000 +0100 +++ linux-source-2.6.15/drivers/scsi/aic7xxx/aic7xxx_osm.h 2006-02-07 11:04:14.000000000 +0100 @@ -368,7 +368,7 @@ struct ahc_platform_data { struct scsi_target *starget[AHC_NUM_TARGETS]; spinlock_t spin_lock; - u_int qfrozen; + atomic_t qfrozen; struct completion *eh_done; struct Scsi_Host *host; /* pointer to scsi host */ #define AHC_LINUX_NOIRQ ((uint32_t)~0)