static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
				    struct done_list_struct *dl)
{
	struct asd_ha_struct *asd_ha = ascb->ha;
	unsigned long flags;
	struct tc_resp_sb_struct {
		__le16 index_escb;
		u8     len_lsb;
		u8     flags;
	} __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;

	int  edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
	struct asd_ascb *escb;
	struct asd_dma_tok *edb;
	struct ssp_frame_hdr *fh;
	struct ssp_response_iu   *ru;
	int res = TMF_RESP_FUNC_FAILED;

	ASD_DPRINTK("tmf resp tasklet\n");

	spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
	escb = asd_tc_index_find(&asd_ha->seq,
				 (int)le16_to_cpu(resp_sb->index_escb));
	spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);

	if (!escb) {
		ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
		return res;
	}

	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
	ascb->tag = *(__be16 *)(edb->vaddr+4);
	fh = edb->vaddr + 16;
	ru = edb->vaddr + 16 + sizeof(*fh);
	res = ru->status;
	if (ru->datapres == 1)	  /* Response data present */
		res = ru->resp_data[3];
#if 0
	ascb->tag = fh->tag;
#endif
	ascb->tag_valid = 1;

	asd_invalidate_edb(escb, edb_id);
	return res;
}
Пример #2
0
static void asd_get_response_tasklet(struct asd_ascb *ascb,
				     struct done_list_struct *dl)
{
	struct asd_ha_struct *asd_ha = ascb->ha;
	struct sas_task *task = ascb->uldd_task;
	struct task_status_struct *ts = &task->task_status;
	unsigned long flags;
	struct tc_resp_sb_struct {
		__le16 index_escb;
		u8     len_lsb;
		u8     flags;
	} __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;

/* 	int  size   = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */
	int  edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
	struct asd_ascb *escb;
	struct asd_dma_tok *edb;
	void *r;

	spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
	escb = asd_tc_index_find(&asd_ha->seq,
				 (int)le16_to_cpu(resp_sb->index_escb));
	spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);

	if (!escb) {
		ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
		return;
	}

	ts->buf_valid_size = 0;
	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
	r = edb->vaddr;
	if (task->task_proto == SAS_PROTO_SSP) {
		struct ssp_response_iu *iu =
			r + 16 + sizeof(struct ssp_frame_hdr);

		ts->residual = le32_to_cpu(*(__le32 *)r);
		ts->resp = SAS_TASK_COMPLETE;
		if (iu->datapres == 0)
			ts->stat = iu->status;
		else if (iu->datapres == 1)
			ts->stat = iu->resp_data[3];
		else if (iu->datapres == 2) {
			ts->stat = SAM_CHECK_COND;
			ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
					 be32_to_cpu(iu->sense_data_len));
			memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
			if (iu->status != SAM_CHECK_COND) {
				ASD_DPRINTK("device %llx sent sense data, but "
					    "stat(0x%x) is not CHECK_CONDITION"
					    "\n",
					    SAS_ADDR(task->dev->sas_addr),
					    ts->stat);
			}
		}
	}  else {
		struct ata_task_resp *resp = (void *) &ts->buf[0];

		ts->residual = le32_to_cpu(*(__le32 *)r);

		if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
			resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
			memcpy(&resp->ending_fis[0], r+16, 24);
			ts->buf_valid_size = sizeof(*resp);
		}
	}

	asd_invalidate_edb(escb, edb_id);
}