That patch is a little more complicated than the others. advansys was the only ISA driver who actually passed ->cmnd to the firmware. So I implemented a simple own bounce buffer scheme for this case. Also did sense_buffer bouncing in the driver while I was at it; which means it doesn't require the mid layer to do this anymore. - allocate hostdata with GFP_DMA separately for the ISA case - Tell block layer explicitely to bounce for ISA case - remove unchecked_isa_dma Untested due to lack of hardware v2: use dma api for all allocations v3: remove cmnd buffer bouncing (thanks m.willcox), move sense bouncing to mid layer Signed-off-by: Andi Kleen <ak@xxxxxxx> Signed-off-by: Andi Kleen <andi@xxxxxxxxxxxxxx> Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx> --- drivers/scsi/advansys.c | 162 ++++++++++++++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 59 deletions(-) Index: linux/drivers/scsi/advansys.c =================================================================== --- linux.orig/drivers/scsi/advansys.c 2008-11-15 22:37:11.000000000 +0100 +++ linux/drivers/scsi/advansys.c 2008-11-15 22:37:12.000000000 +0100 @@ -2212,7 +2212,7 @@ #define ASC_STATS_ADD(shost, counter, count) #else /* ADVANSYS_STATS */ #define ASC_STATS_ADD(shost, counter, count) \ - (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count)) + (asc_shost_priv(shost)->asc_stats.counter += (count)) #endif /* ADVANSYS_STATS */ /* If the result wraps when calculating tenths, return 0. */ @@ -2354,10 +2354,6 @@ /* * Structure allocated for each board. - * - * This structure is allocated by scsi_host_alloc() at the end - * of the 'Scsi_Host' structure starting at the 'hostdata' - * field. It is guaranteed to be allocated from DMA-able memory. */ struct asc_board { struct device *dev; @@ -2388,6 +2384,7 @@ #ifdef ADVANSYS_STATS struct asc_stats asc_stats; /* Board statistics */ #endif /* ADVANSYS_STATS */ + /* * The following fields are used only for Narrow Boards. */ @@ -2403,8 +2400,19 @@ ushort bios_version; /* BIOS Version. */ ushort bios_codeseg; /* BIOS Code Segment. */ ushort bios_codelen; /* BIOS Code Segment Length. */ + +}; + +struct asc_board_ptr { + struct asc_board *b; + dma_addr_t dma; }; + + +#define asc_shost_priv(h) (((struct asc_board_ptr *)shost_priv(h))->b) +#define asc_shost_dma(h) (((struct asc_board_ptr *)shost_priv(h))->dma) + #define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \ dvc_var.asc_dvc_var) #define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \ @@ -2525,7 +2533,7 @@ */ static void asc_prt_scsi_host(struct Scsi_Host *s) { - struct asc_board *boardp = shost_priv(s); + struct asc_board *boardp = asc_shost_priv(s); printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id); printk(" host_busy %u, host_no %d, last_reset %d,\n", @@ -2537,8 +2545,8 @@ printk(" dma_channel %d, this_id %d, can_queue %d,\n", s->dma_channel, s->this_id, s->can_queue); - printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n", - s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma); + printk(" cmd_per_lun %d, sg_tablesize %d\n", + s->cmd_per_lun, s->sg_tablesize); if (ASC_NARROW_BOARD(boardp)) { asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var); @@ -2803,7 +2811,7 @@ static const char *advansys_info(struct Scsi_Host *shost) { static char info[ASC_INFO_SIZE]; - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); ASC_DVC_VAR *asc_dvc_varp; ADV_DVC_VAR *adv_dvc_varp; char *busname; @@ -2919,7 +2927,7 @@ */ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); int leftlen; int totlen; int len; @@ -2959,7 +2967,7 @@ */ static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); int leftlen; int totlen; int len; @@ -3124,7 +3132,7 @@ */ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); ASC_DVC_VAR *asc_dvc_varp; int leftlen; int totlen; @@ -3257,7 +3265,7 @@ */ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); ADV_DVC_VAR *adv_dvc_varp; int leftlen; int totlen; @@ -3543,7 +3551,7 @@ */ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); int leftlen; int totlen; int len; @@ -3569,9 +3577,7 @@ shost->sg_tablesize, shost->cmd_per_lun); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - " unchecked_isa_dma %d, use_clustering %d\n", - shost->unchecked_isa_dma, shost->use_clustering); + len = asc_prt_line(cp, leftlen, " use_clustering %d\n", shost->use_clustering); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -3605,7 +3611,7 @@ */ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); int chip_scsi_id; int leftlen; int totlen; @@ -3787,7 +3793,7 @@ */ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); int leftlen; int totlen; int len; @@ -4065,7 +4071,7 @@ */ static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); struct asc_stats *s = &boardp->asc_stats; int leftlen = cplen; @@ -4151,7 +4157,7 @@ advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); char *cp; int cplen; int cnt; @@ -8200,7 +8206,7 @@ ASC_STATS(shost, callback); ASC_DBG(1, "shost 0x%p\n", shost); - boardp = shost_priv(shost); + boardp = asc_shost_priv(shost); BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var); /* @@ -9132,7 +9138,7 @@ ASC_STATS(shost, callback); ASC_DBG(1, "shost 0x%p\n", shost); - boardp = shost_priv(shost); + boardp = asc_shost_priv(shost); BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); dma_unmap_single(boardp->dev, scp->SCp.dma_handle, @@ -9484,7 +9490,7 @@ static int advansys_reset(struct scsi_cmnd *scp) { struct Scsi_Host *shost = scp->device->host; - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); unsigned long flags; int status; int ret = SUCCESS; @@ -9567,7 +9573,7 @@ advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int ip[]) { - struct asc_board *boardp = shost_priv(sdev->host); + struct asc_board *boardp = asc_shost_priv(sdev->host); ASC_DBG(1, "begin\n"); ASC_STATS(sdev->host, biosparam); @@ -9603,7 +9609,7 @@ static irqreturn_t advansys_interrupt(int irq, void *dev_id) { struct Scsi_Host *shost = dev_id; - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); irqreturn_t result = IRQ_NONE; ASC_DBG(2, "boardp 0x%p\n", boardp); @@ -9691,6 +9697,9 @@ ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id; ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng; + if (sdev->host->sense_buffer_isa) + blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ISA); + if (sdev->lun == 0) { ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr; if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) { @@ -9865,7 +9874,7 @@ */ static int advansys_slave_configure(struct scsi_device *sdev) { - struct asc_board *boardp = shost_priv(sdev->host); + struct asc_board *boardp = asc_shost_priv(sdev->host); if (ASC_NARROW_BOARD(boardp)) advansys_narrow_slave_configure(sdev, @@ -10925,7 +10934,7 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) { int ret, err_code; - struct asc_board *boardp = shost_priv(scp->device->host); + struct asc_board *boardp = asc_shost_priv(scp->device->host); ASC_DBG(1, "scp 0x%p\n", scp); @@ -11725,7 +11734,7 @@ static int __devinit AscInitGetConfig(struct Scsi_Host *shost) { - struct asc_board *board = shost_priv(shost); + struct asc_board *board = asc_shost_priv(shost); ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; unsigned short warn_code = 0; @@ -11779,7 +11788,7 @@ static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) { - struct asc_board *board = shost_priv(shost); + struct asc_board *board = asc_shost_priv(shost); ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; PortAddr iop_base = asc_dvc->iop_base; unsigned short cfg_msw; @@ -13172,7 +13181,7 @@ static int __devinit AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) { - struct asc_board *board = shost_priv(shost); + struct asc_board *board = asc_shost_priv(shost); ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var; unsigned short warn_code = 0; AdvPortAddr iop_base = asc_dvc->iop_base; @@ -13250,6 +13259,13 @@ } #endif +static int advansys_adjust_queue(struct scsi_device *device) +{ + if (device->host->sense_buffer_isa) + blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA); + return 0; +} + static struct scsi_host_template advansys_template = { .proc_name = DRV_NAME, #ifdef CONFIG_PROC_FS @@ -13261,12 +13277,7 @@ .eh_bus_reset_handler = advansys_reset, .bios_param = advansys_biosparam, .slave_configure = advansys_slave_configure, - /* - * Because the driver may control an ISA adapter 'unchecked_isa_dma' - * must be set. The flag will be cleared in advansys_board_found - * for non-ISA adapters. - */ - .unchecked_isa_dma = 1, + .slave_alloc = advansys_adjust_queue, /* * All adapters controlled by this driver are capable of large * scatter-gather lists. According to the mid-level SCSI documentation @@ -13279,7 +13290,7 @@ static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost) { - struct asc_board *board = shost_priv(shost); + struct asc_board *board = asc_shost_priv(shost); struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var; int req_cnt = 0; adv_req_t *reqp = NULL; @@ -13394,7 +13405,7 @@ unsigned int iop, int bus_type) { struct pci_dev *pdev; - struct asc_board *boardp = shost_priv(shost); + struct asc_board *boardp = asc_shost_priv(shost); ASC_DVC_VAR *asc_dvc_varp = NULL; ADV_DVC_VAR *adv_dvc_varp = NULL; int share_irq, warn_code, ret; @@ -13464,6 +13475,8 @@ } #endif /* CONFIG_PROC_FS */ + ret = 0; + if (ASC_NARROW_BOARD(boardp)) { /* * Set the board bus type and PCI IRQ before @@ -13472,28 +13485,23 @@ switch (asc_dvc_varp->bus_type) { #ifdef CONFIG_ISA case ASC_IS_ISA: - shost->unchecked_isa_dma = TRUE; share_irq = 0; break; case ASC_IS_VL: - shost->unchecked_isa_dma = FALSE; share_irq = 0; break; case ASC_IS_EISA: - shost->unchecked_isa_dma = FALSE; share_irq = IRQF_SHARED; break; #endif /* CONFIG_ISA */ #ifdef CONFIG_PCI case ASC_IS_PCI: - shost->unchecked_isa_dma = FALSE; share_irq = IRQF_SHARED; break; #endif /* CONFIG_PCI */ default: shost_printk(KERN_ERR, shost, "unknown adapter type: " "%d\n", asc_dvc_varp->bus_type); - shost->unchecked_isa_dma = TRUE; share_irq = 0; break; } @@ -13505,14 +13513,14 @@ * referenced only use the bit-wise AND operator "&". */ ASC_DBG(2, "AscInitGetConfig()\n"); - ret = AscInitGetConfig(shost) ? -ENODEV : 0; + if (!ret) + ret = AscInitGetConfig(shost) ? -ENODEV : 0; } else { #ifdef CONFIG_PCI /* * For Wide boards set PCI information before calling * AdvInitGetConfig(). */ - shost->unchecked_isa_dma = FALSE; share_irq = IRQF_SHARED; ASC_DBG(2, "AdvInitGetConfig()\n"); @@ -13883,6 +13891,16 @@ return ret; } +static void adv_free_host(struct Scsi_Host *shost) +{ + struct asc_board *board = asc_shost_priv(shost); + struct device *device = board->dev; + dma_free_coherent(device, sizeof(struct asc_board), + asc_shost_priv(shost), + asc_shost_dma(shost)); + scsi_host_put(shost); +} + /* * advansys_release() * @@ -13890,7 +13908,7 @@ */ static int advansys_release(struct Scsi_Host *shost) { - struct asc_board *board = shost_priv(shost); + struct asc_board *board = asc_shost_priv(shost); ASC_DBG(1, "begin\n"); scsi_remove_host(shost); free_irq(board->irq, shost); @@ -13908,11 +13926,32 @@ advansys_wide_free_mem(board); } kfree(board->prtbuf); - scsi_host_put(shost); + adv_free_host(shost); ASC_DBG(1, "end\n"); return 0; } +static struct Scsi_Host *adv_host_alloc(struct device *dev) +{ + struct asc_board *board; + struct Scsi_Host *shost; + shost = scsi_host_alloc(&advansys_template, + sizeof(struct asc_board_ptr)); + if (!shost) + return NULL; + + board = dma_alloc_coherent(dev, + sizeof(struct asc_board), + &asc_shost_dma(shost), + GFP_KERNEL); + if (!board) { + scsi_host_put(shost); + return NULL; + } + asc_shost_priv(shost) = board; + return shost; +} + #define ASC_IOADR_TABLE_MAX_IX 11 static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = { @@ -13954,11 +13993,13 @@ goto release_region; err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + shost = adv_host_alloc(NULL); if (!shost) goto release_region; + shost->sense_buffer_isa = 1; + + board = asc_shost_priv(shost); - board = shost_priv(shost); board->irq = advansys_isa_irq_no(iop_base); board->dev = dev; @@ -13970,7 +14011,7 @@ return 0; free_host: - scsi_host_put(shost); + adv_free_host(shost); release_region: release_region(iop_base, ASC_IOADR_GAP); return err; @@ -14036,11 +14077,12 @@ goto release_region; err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + shost = adv_host_alloc(NULL); if (!shost) goto release_region; + shost->sense_buffer_isa = 1; - board = shost_priv(shost); + board = asc_shost_priv(shost); board->irq = advansys_vlb_irq_no(iop_base); board->dev = dev; @@ -14052,7 +14094,7 @@ return 0; free_host: - scsi_host_put(shost); + adv_free_host(shost); release_region: release_region(iop_base, ASC_IOADR_GAP); return -ENODEV; @@ -14143,11 +14185,13 @@ irq = advansys_eisa_irq_no(edev); err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + /* RED-PEN does use GFP_DMA unnecessarily since EISA is 32bit */ + shost = adv_host_alloc(NULL); + if (!shost) goto release_region; - board = shost_priv(shost); + board = asc_shost_priv(shost); board->irq = irq; board->dev = dev; @@ -14259,11 +14303,11 @@ ioport = pci_resource_start(pdev, 0); err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + shost = adv_host_alloc(&pdev->dev); if (!shost) goto release_region; - board = shost_priv(shost); + board = asc_shost_priv(shost); board->irq = pdev->irq; board->dev = &pdev->dev; @@ -14281,7 +14325,7 @@ return 0; free_host: - scsi_host_put(shost); + adv_free_host(shost); release_region: pci_release_regions(pdev); disable_device: -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html