Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b47e464 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by James Bottomley
Browse files

advansys: Use DMA-API for mapping request blocks

parent 98b96a7d
Loading
Loading
Loading
Loading
+54 −54
Original line number Original line Diff line number Diff line
@@ -1894,11 +1894,11 @@ typedef struct adv_sgblk {


typedef struct adv_req {
typedef struct adv_req {
	ADV_SCSI_REQ_Q scsi_req_q;	/* Adv Library request structure. */
	ADV_SCSI_REQ_Q scsi_req_q;	/* Adv Library request structure. */
	uchar align[32];	/* Request structure padding. */
	uchar align[24];	/* Request structure padding. */
	struct scsi_cmnd *cmndp;	/* Mid-Level SCSI command pointer. */
	struct scsi_cmnd *cmndp;	/* Mid-Level SCSI command pointer. */
	dma_addr_t req_addr;
	adv_sgblk_t *sgblkp;	/* Adv Library scatter-gather pointer. */
	adv_sgblk_t *sgblkp;	/* Adv Library scatter-gather pointer. */
	struct adv_req *next_reqp;	/* Next Request Structure. */
} adv_req_t __aligned(32);
} adv_req_t;


/*
/*
 * Adapter operation variable structure.
 * Adapter operation variable structure.
@@ -2379,6 +2379,8 @@ struct asc_board {
	void __iomem *ioremap_addr;	/* I/O Memory remap address. */
	void __iomem *ioremap_addr;	/* I/O Memory remap address. */
	ushort ioport;		/* I/O Port address. */
	ushort ioport;		/* I/O Port address. */
	adv_req_t *adv_reqp;	/* Request structures. */
	adv_req_t *adv_reqp;	/* Request structures. */
	dma_addr_t adv_reqp_addr;
	size_t adv_reqp_size;
	adv_sgblk_t *adv_sgblkp;	/* Scatter-gather structures. */
	adv_sgblk_t *adv_sgblkp;	/* Scatter-gather structures. */
	ushort bios_signature;	/* BIOS Signature. */
	ushort bios_signature;	/* BIOS Signature. */
	ushort bios_version;	/* BIOS Version. */
	ushort bios_version;	/* BIOS Version. */
@@ -4383,6 +4385,17 @@ static ADV_CARR_T *adv_get_next_carrier(struct adv_dvc_var *adv_dvc)
	return carrp;
	return carrp;
}
}


/*
 * 'offset' is the index in the request pointer array
 */
static adv_req_t * adv_get_reqp(struct adv_dvc_var *adv_dvc, u32 offset)
{
	struct asc_board *boardp = adv_dvc->drv_ptr;

	BUG_ON(offset > adv_dvc->max_host_qng);
	return &boardp->adv_reqp[offset];
}

/*
/*
 * Send an idle command to the chip and wait for completion.
 * Send an idle command to the chip and wait for completion.
 *
 *
@@ -6229,6 +6242,7 @@ static int AdvISR(ADV_DVC_VAR *asc_dvc)
	ADV_CARR_T *free_carrp;
	ADV_CARR_T *free_carrp;
	ADV_VADDR irq_next_vpa;
	ADV_VADDR irq_next_vpa;
	ADV_SCSI_REQ_Q *scsiq;
	ADV_SCSI_REQ_Q *scsiq;
	adv_req_t *reqp;


	iop_base = asc_dvc->iop_base;
	iop_base = asc_dvc->iop_base;


@@ -6281,8 +6295,11 @@ static int AdvISR(ADV_DVC_VAR *asc_dvc)
		 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
		 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
		 * in AdvExeScsiQueue().
		 * in AdvExeScsiQueue().
		 */
		 */
		scsiq = (ADV_SCSI_REQ_Q *)
		u32 pa_offset = le32_to_cpu(asc_dvc->irq_sp->areq_vpa);
		    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
		ASC_DBG(1, "irq_sp %p areq_vpa %u\n",
			asc_dvc->irq_sp, pa_offset);
		reqp = adv_get_reqp(asc_dvc, pa_offset);
		scsiq = &reqp->scsi_req_q;


		/*
		/*
		 * Request finished with good status and the queue was not
		 * Request finished with good status and the queue was not
@@ -7883,18 +7900,16 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
 *      ADV_ERROR(-1) - SG List creation failed
 *      ADV_ERROR(-1) - SG List creation failed
 */
 */
static int
static int
adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp,
	       int use_sg)
	       ADV_SCSI_REQ_Q *scsiqp, struct scsi_cmnd *scp, int use_sg)
{
{
	adv_sgblk_t *sgblkp;
	adv_sgblk_t *sgblkp;
	ADV_SCSI_REQ_Q *scsiqp;
	struct scatterlist *slp;
	struct scatterlist *slp;
	int sg_elem_cnt;
	int sg_elem_cnt;
	ADV_SG_BLOCK *sg_block, *prev_sg_block;
	ADV_SG_BLOCK *sg_block, *prev_sg_block;
	ADV_PADDR sg_block_paddr;
	ADV_PADDR sg_block_paddr;
	int i;
	int i;


	scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
	slp = scsi_sglist(scp);
	slp = scsi_sglist(scp);
	sg_elem_cnt = use_sg;
	sg_elem_cnt = use_sg;
	prev_sg_block = NULL;
	prev_sg_block = NULL;
@@ -7994,7 +8009,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
 */
 */
static int
static int
adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
	      ADV_SCSI_REQ_Q **adv_scsiqpp)
	      adv_req_t **adv_reqpp)
{
{
	u32 srb_tag = scp->request->tag;
	u32 srb_tag = scp->request->tag;
	adv_req_t *reqp;
	adv_req_t *reqp;
@@ -8014,10 +8029,9 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
		return ASC_BUSY;
		return ASC_BUSY;
	}
	}


	/*
	reqp->req_addr = boardp->adv_reqp_addr + (srb_tag * sizeof(adv_req_t));
	 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.

	 */
	scsiqp = &reqp->scsi_req_q;
	scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);


	/*
	/*
	 * Initialize the structure.
	 * Initialize the structure.
@@ -8030,7 +8044,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
	scsiqp->srb_tag = srb_tag;
	scsiqp->srb_tag = srb_tag;


	/*
	/*
	 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
	 * Set 'host_scribble' to point to the adv_req_t structure.
	 */
	 */
	reqp->cmndp = scp;
	reqp->cmndp = scp;
	scp->host_scribble = (void *)reqp;
	scp->host_scribble = (void *)reqp;
@@ -8084,7 +8098,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,


		scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));
		scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));


		ret = adv_get_sglist(boardp, reqp, scp, use_sg);
		ret = adv_get_sglist(boardp, reqp, scsiqp, scp, use_sg);
		if (ret != ADV_SUCCESS) {
		if (ret != ADV_SUCCESS) {
			scsi_dma_unmap(scp);
			scsi_dma_unmap(scp);
			scp->result = HOST_BYTE(DID_ERROR);
			scp->result = HOST_BYTE(DID_ERROR);
@@ -8102,7 +8116,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
	ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
	ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);


	*adv_scsiqpp = scsiqp;
	*adv_reqpp = reqp;


	return ASC_NOERROR;
	return ASC_NOERROR;
}
}
@@ -8692,11 +8706,11 @@ static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
 *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
 *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
 *                       host IC error.
 *                       host IC error.
 */
 */
static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, adv_req_t *reqp)
{
{
	AdvPortAddr iop_base;
	AdvPortAddr iop_base;
	ADV_PADDR req_paddr;
	ADV_CARR_T *new_carrp;
	ADV_CARR_T *new_carrp;
	ADV_SCSI_REQ_Q *scsiq = &reqp->scsi_req_q;


	/*
	/*
	 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
	 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
@@ -8726,14 +8740,9 @@ static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
	 */
	 */
	scsiq->a_flag &= ~ADV_SCSIQ_DONE;
	scsiq->a_flag &= ~ADV_SCSIQ_DONE;


	req_paddr = virt_to_bus(scsiq);
	BUG_ON(req_paddr & 31);
	/* Wait for assertion before making little-endian */
	req_paddr = cpu_to_le32(req_paddr);

	/* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
	/* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
	scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
	scsiq->scsiq_ptr = cpu_to_le32(scsiq->srb_tag);
	scsiq->scsiq_rptr = req_paddr;
	scsiq->scsiq_rptr = cpu_to_le32(reqp->req_addr);


	scsiq->carr_va = asc_dvc->icq_sp->carr_va;
	scsiq->carr_va = asc_dvc->icq_sp->carr_va;
	scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
	scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
@@ -8743,7 +8752,7 @@ static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
	 * the microcode. The newly allocated stopper will become the new
	 * the microcode. The newly allocated stopper will become the new
	 * stopper.
	 * stopper.
	 */
	 */
	asc_dvc->icq_sp->areq_vpa = req_paddr;
	asc_dvc->icq_sp->areq_vpa = scsiq->scsiq_rptr;


	/*
	/*
	 * Set the 'next_vpa' pointer for the old stopper to be the
	 * Set the 'next_vpa' pointer for the old stopper to be the
@@ -8810,9 +8819,9 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
		err_code = asc_dvc->err_code;
		err_code = asc_dvc->err_code;
	} else {
	} else {
		ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
		ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
		ADV_SCSI_REQ_Q *adv_scsiqp;
		adv_req_t *adv_reqp;


		switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
		switch (adv_build_req(boardp, scp, &adv_reqp)) {
		case ASC_NOERROR:
		case ASC_NOERROR:
			ASC_DBG(3, "adv_build_req ASC_NOERROR\n");
			ASC_DBG(3, "adv_build_req ASC_NOERROR\n");
			break;
			break;
@@ -8832,7 +8841,7 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
			return ASC_ERROR;
			return ASC_ERROR;
		}
		}


		ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp);
		ret = AdvExeScsiQueue(adv_dvc, adv_reqp);
		err_code = adv_dvc->err_code;
		err_code = adv_dvc->err_code;
	}
	}


@@ -8847,6 +8856,7 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
		ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n");
		ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n");
		break;
		break;
	case ASC_BUSY:
	case ASC_BUSY:
		ASC_DBG(1, "ExeScsiQueue() ASC_BUSY\n");
		ASC_STATS(scp->device->host, exe_busy);
		ASC_STATS(scp->device->host, exe_busy);
		break;
		break;
	case ASC_ERROR:
	case ASC_ERROR:
@@ -11147,8 +11157,6 @@ static int advansys_wide_init_chip(struct Scsi_Host *shost)
{
{
	struct asc_board *board = shost_priv(shost);
	struct asc_board *board = shost_priv(shost);
	struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
	struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
	int req_cnt = 0;
	adv_req_t *reqp = NULL;
	int sg_cnt = 0;
	int sg_cnt = 0;
	adv_sgblk_t *sgp;
	adv_sgblk_t *sgp;
	int warn_code, err_code;
	int warn_code, err_code;
@@ -11169,20 +11177,19 @@ static int advansys_wide_init_chip(struct Scsi_Host *shost)
	 * board. The total size is about 16 KB, so allocate all at once.
	 * board. The total size is about 16 KB, so allocate all at once.
	 * If the allocation fails decrement and try again.
	 * If the allocation fails decrement and try again.
	 */
	 */
	for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) {
	board->adv_reqp_size = adv_dvc->max_host_qng * sizeof(adv_req_t);
		reqp = kzalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
	if (board->adv_reqp_size & 0x1f) {

		ASC_DBG(1, "unaligned reqp %lu bytes\n", sizeof(adv_req_t));
		ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt,
		board->adv_reqp_size = ADV_32BALIGN(board->adv_reqp_size);
			 (ulong)sizeof(adv_req_t) * req_cnt);

		if (reqp)
			break;
	}
	}
	board->adv_reqp = dma_alloc_coherent(board->dev, board->adv_reqp_size,
		&board->adv_reqp_addr, GFP_KERNEL);


	if (!reqp)
	if (!board->adv_reqp)
		goto kmalloc_failed;
		goto kmalloc_failed;


	board->adv_reqp = reqp;
	ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", board->adv_reqp,
		adv_dvc->max_host_qng, board->adv_reqp_size);


	/*
	/*
	 * Allocate up to ADV_TOT_SG_BLOCK request structures for
	 * Allocate up to ADV_TOT_SG_BLOCK request structures for
@@ -11206,16 +11213,6 @@ static int advansys_wide_init_chip(struct Scsi_Host *shost)
	if (!board->adv_sgblkp)
	if (!board->adv_sgblkp)
		goto kmalloc_failed;
		goto kmalloc_failed;


	/*
	 * Point 'adv_reqp' to the request structures and
	 * link them together.
	 */
	req_cnt--;
	reqp[req_cnt].next_reqp = NULL;
	for (; req_cnt > 0; req_cnt--) {
		reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
	}

	if (adv_dvc->chip_type == ADV_CHIP_ASC3550) {
	if (adv_dvc->chip_type == ADV_CHIP_ASC3550) {
		ASC_DBG(2, "AdvInitAsc3550Driver()\n");
		ASC_DBG(2, "AdvInitAsc3550Driver()\n");
		warn_code = AdvInitAsc3550Driver(adv_dvc);
		warn_code = AdvInitAsc3550Driver(adv_dvc);
@@ -11251,8 +11248,11 @@ static void advansys_wide_free_mem(struct asc_board *board)
				  adv_dvc->carrier, adv_dvc->carrier_addr);
				  adv_dvc->carrier, adv_dvc->carrier_addr);
		adv_dvc->carrier = NULL;
		adv_dvc->carrier = NULL;
	}
	}
	kfree(board->adv_reqp);
	if (board->adv_reqp) {
		dma_free_coherent(board->dev, board->adv_reqp_size,
				  board->adv_reqp, board->adv_reqp_addr);
		board->adv_reqp = NULL;
		board->adv_reqp = NULL;
	}
	while (board->adv_sgblkp) {
	while (board->adv_sgblkp) {
		adv_sgblk_t *sgp = board->adv_sgblkp;
		adv_sgblk_t *sgp = board->adv_sgblkp;
		board->adv_sgblkp = sgp->next_sgblkp;
		board->adv_sgblkp = sgp->next_sgblkp;