X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fadvansys.c;h=8591585e5cc55c27669a004c48c048521a3dc9e4;hb=d2532dd20a126020de407c1c2476a75b53fce7ac;hp=d35897eaa807d936a0c4676037fe155ea9d6a867;hpb=52c334e9450a15230b84ab4ef8ef7b034b37c371;p=linux-2.6 diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index d35897eaa8..8591585e5c 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -90,17 +90,6 @@ #define ASC_DCNT __u32 /* Unsigned Data count type. */ #define ASC_SDCNT __s32 /* Signed Data count type. */ -/* - * These macros are used to convert a virtual address to a - * 32-bit value. This currently can be used on Linux Alpha - * which uses 64-bit virtual address but a 32-bit bus address. - * This is likely to break in the future, but doing this now - * will give us time to change the HW and FW to handle 64-bit - * addresses. - */ -#define ASC_VADDR_TO_U32 virt_to_bus -#define ASC_U32_TO_VADDR bus_to_virt - typedef unsigned char uchar; #ifndef TRUE @@ -131,7 +120,7 @@ typedef unsigned char uchar; #define CC_VERY_LONG_SG_LIST 0 #define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) -#define PortAddr unsigned short /* port address size */ +#define PortAddr unsigned int /* port address size */ #define inp(port) inb(port) #define outp(port, byte) outb((byte), (port)) @@ -540,7 +529,6 @@ typedef struct asc_dvc_cfg { ushort mcode_date; ushort mcode_version; uchar max_tag_qng[ASC_MAX_TID + 1]; - uchar *overrun_buf; uchar sdtr_period_offset[ASC_MAX_TID + 1]; uchar adapter_info[6]; } ASC_DVC_CFG; @@ -562,6 +550,7 @@ typedef struct asc_dvc_cfg { #define ASC_BUG_FIX_ASYN_USE_SYN 0x0002 #define ASC_MIN_TAGGED_CMD 7 #define ASC_MAX_SCSI_RESET_WAIT 30 +#define ASC_OVERRUN_BSIZE 64 struct asc_dvc_var; /* Forward Declaration. */ @@ -577,6 +566,8 @@ typedef struct asc_dvc_var { ASC_SCSI_BIT_ID_TYPE unit_not_ready; ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; ASC_SCSI_BIT_ID_TYPE start_motor; + uchar *overrun_buf; + dma_addr_t overrun_dma; uchar scsi_reset_wait; uchar chip_no; char is_in_int; @@ -601,6 +592,8 @@ typedef struct asc_dvc_var { uchar min_sdtr_index; uchar max_sdtr_index; struct asc_board *drv_ptr; + int ptr_map_count; + void **ptr_map; ASC_DCNT uc_break; } ASC_DVC_VAR; @@ -677,7 +670,6 @@ typedef struct asceep_config { #define ASC_EEP_CMD_WRITE 0x40 #define ASC_EEP_CMD_WRITE_ABLE 0x30 #define ASC_EEP_CMD_WRITE_DISABLE 0x00 -#define ASC_OVERRUN_BSIZE 0x00000048UL #define ASCV_MSGOUT_BEG 0x0000 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3) #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4) @@ -2413,13 +2405,12 @@ struct asc_board { ushort bios_codelen; /* BIOS Code Segment Length. */ }; +#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, \ dvc_var.adv_dvc_var) #define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev) -/* Overrun buffer used by all narrow boards. */ -static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; - #ifdef ADVANSYS_DEBUG static int asc_dbglvl = 3; @@ -2474,8 +2465,8 @@ static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel, h->chip_version); - printk(" mcode_date 0x%x, mcode_version %d, overrun_buf 0x%p\n", - h->mcode_date, h->mcode_version, h->overrun_buf); + printk(" mcode_date 0x%x, mcode_version %d\n", + h->mcode_date, h->mcode_version); } /* @@ -2747,6 +2738,59 @@ static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) } #endif /* ADVANSYS_DEBUG */ +/* + * The advansys chip/microcode contains a 32-bit identifier for each command + * known as the 'srb'. I don't know what it stands for. The driver used + * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it + * with bus_to_virt. Now the driver keeps a per-host map of integers to + * pointers. It auto-expands when full, unless it can't allocate memory. + * Note that an srb of 0 is treated specially by the chip/firmware, hence + * the return of i+1 in this routine, and the corresponding subtraction in + * the inverse routine. + */ +#define BAD_SRB 0 +static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr) +{ + int i; + void **new_ptr; + + for (i = 0; i < asc_dvc->ptr_map_count; i++) { + if (!asc_dvc->ptr_map[i]) + goto out; + } + + if (asc_dvc->ptr_map_count == 0) + asc_dvc->ptr_map_count = 1; + else + asc_dvc->ptr_map_count *= 2; + + new_ptr = krealloc(asc_dvc->ptr_map, + asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC); + if (!new_ptr) + return BAD_SRB; + asc_dvc->ptr_map = new_ptr; + out: + ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i); + asc_dvc->ptr_map[i] = ptr; + return i + 1; +} + +static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb) +{ + void *ptr; + + srb--; + if (srb >= asc_dvc->ptr_map_count) { + printk("advansys: bad SRB %u, max %u\n", srb, + asc_dvc->ptr_map_count); + return NULL; + } + ptr = asc_dvc->ptr_map[srb]; + asc_dvc->ptr_map[srb] = NULL; + ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb); + return ptr; +} + /* * advansys_info() * @@ -6272,6 +6316,7 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) PortAddr iop_base; ASC_PADDR phy_addr; ASC_DCNT phy_size; + struct asc_board *board = asc_dvc_to_board(asc_dvc); iop_base = asc_dvc->iop_base; warn_code = 0; @@ -6286,12 +6331,14 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); - /* Align overrun buffer on an 8 byte boundary. */ - phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf); - phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); + /* Ensure overrun buffer is aligned on an 8 byte boundary. */ + BUG_ON((unsigned long)asc_dvc->overrun_buf & 7); + asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf, + ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + phy_addr = cpu_to_le32(asc_dvc->overrun_dma); AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, (uchar *)&phy_addr, 1); - phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8); + phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE); AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, (uchar *)&phy_size, 1); @@ -6392,7 +6439,7 @@ static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size, i += 2; len += 2; } else { - unsigned char off = buf[i] * 2; + unsigned int off = buf[i] * 2; unsigned short word = (buf[off + 1] << 8) | buf[off]; AdvWriteWordAutoIncLram(iop_base, word); len += 2; @@ -8186,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) { ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); /* * Note: The 'status_byte()' macro used by * target drivers defined in scsi.h shifts the @@ -9075,17 +9122,10 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep); ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); - /* - * Get the struct scsi_cmnd structure and Scsi_Host structure for the - * command that has been completed. - */ - scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr); - ASC_DBG(1, "scp 0x%p\n", scp); - - if (scp == NULL) { - ASC_PRINT("asc_isr_callback: scp is NULL\n"); + scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr); + if (!scp) return; - } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); shost = scp->device->host; @@ -9095,6 +9135,8 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) boardp = shost_priv(shost); BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); + dma_unmap_single(boardp->dev, scp->SCp.dma_handle, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); /* * 'qdonep' contains the command's ending status. */ @@ -9124,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) { ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); /* * Note: The 'status_byte()' macro used by * target drivers defined in scsi.h shifts the @@ -9835,9 +9877,20 @@ static int advansys_slave_configure(struct scsi_device *sdev) return 0; } +static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp) +{ + struct asc_board *board = shost_priv(scp->device->host); + scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + dma_cache_sync(board->dev, scp->sense_buffer, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + return cpu_to_le32(scp->SCp.dma_handle); +} + static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, struct asc_scsi_q *asc_scsi_q) { + struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var; int use_sg; memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); @@ -9845,7 +9898,11 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, /* * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. */ - asc_scsi_q->q2.srb_ptr = ASC_VADDR_TO_U32(scp); + asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp); + if (asc_scsi_q->q2.srb_ptr == BAD_SRB) { + scp->result = HOST_BYTE(DID_SOFT_ERROR); + return ASC_ERROR; + } /* * Build the ASC_SCSI_Q request. @@ -9856,9 +9913,8 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, asc_scsi_q->q1.target_lun = scp->device->lun; asc_scsi_q->q2.target_ix = ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); - asc_scsi_q->q1.sense_addr = - cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); + asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp); + asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE; /* * If there are any outstanding requests for the current target, @@ -9871,7 +9927,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, * started request. * */ - if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) && + if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) && (boardp->reqcnt[scp->device->id] % 255) == 0) { asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; } else { @@ -10091,7 +10147,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, /* * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. */ - scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp); + scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp); /* * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. @@ -10117,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, scsiqp->target_lun = scp->device->lun; scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - scsiqp->sense_len = sizeof(scp->sense_buffer); + scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE; /* Build ADV_SCSI_REQ_Q */ @@ -12205,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) { ushort *wbuf; @@ -12272,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; @@ -12339,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) { ushort *wbuf; @@ -13277,8 +13333,8 @@ static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost) } - ASC_DBG(1, "sg_cnt %d * %u = %u bytes\n", sg_cnt, sizeof(adv_sgblk_t), - (unsigned)(sizeof(adv_sgblk_t) * sg_cnt)); + ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t), + sizeof(adv_sgblk_t) * sg_cnt); if (!board->adv_sgblkp) goto kmalloc_failed; @@ -13351,7 +13407,6 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, asc_dvc_varp->bus_type = bus_type; asc_dvc_varp->drv_ptr = boardp; asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg; - asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; asc_dvc_varp->iop_base = iop; } else { #ifdef CONFIG_PCI @@ -13373,9 +13428,9 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1), boardp->asc_n_io_port); if (!boardp->ioremap_addr) { - shost_printk(KERN_ERR, shost, "ioremap(%x, %d) " + shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) " "returned NULL\n", - pci_resource_start(pdev, 1), + (long)pci_resource_start(pdev, 1), boardp->asc_n_io_port); ret = -ENODEV; goto err_shost; @@ -13778,6 +13833,12 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, */ if (ASC_NARROW_BOARD(boardp)) { ASC_DBG(2, "AscInitAsc1000Driver()\n"); + + asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL); + if (!asc_dvc_varp->overrun_buf) { + ret = -ENOMEM; + goto err_free_wide_mem; + } warn_code = AscInitAsc1000Driver(asc_dvc_varp); if (warn_code || asc_dvc_varp->err_code) { @@ -13785,8 +13846,10 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, "warn 0x%x, error 0x%x\n", asc_dvc_varp->init_state, warn_code, asc_dvc_varp->err_code); - if (asc_dvc_varp->err_code) + if (asc_dvc_varp->err_code) { ret = -ENODEV; + kfree(asc_dvc_varp->overrun_buf); + } } } else { if (advansys_wide_init_chip(shost)) @@ -13827,19 +13890,24 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, */ static int advansys_release(struct Scsi_Host *shost) { - struct asc_board *boardp = shost_priv(shost); + struct asc_board *board = shost_priv(shost); ASC_DBG(1, "begin\n"); scsi_remove_host(shost); - free_irq(boardp->irq, shost); + free_irq(board->irq, shost); if (shost->dma_channel != NO_ISA_DMA) { ASC_DBG(1, "free_dma()\n"); free_dma(shost->dma_channel); } - if (!ASC_NARROW_BOARD(boardp)) { - iounmap(boardp->ioremap_addr); - advansys_wide_free_mem(boardp); + if (ASC_NARROW_BOARD(board)) { + dma_unmap_single(board->dev, + board->dvc_var.asc_dvc_var.overrun_dma, + ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + kfree(board->dvc_var.asc_dvc_var.overrun_buf); + } else { + iounmap(board->ioremap_addr); + advansys_wide_free_mem(board); } - kfree(boardp->prtbuf); + kfree(board->prtbuf); scsi_host_put(shost); ASC_DBG(1, "end\n"); return 0; @@ -13847,7 +13915,7 @@ static int advansys_release(struct Scsi_Host *shost) #define ASC_IOADR_TABLE_MAX_IX 11 -static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = { +static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = { 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190, 0x0210, 0x0230, 0x0250, 0x0330 };