pmcs_sata.c revision 11048:6da57c1c6564
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 *
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * SATA midlayer interface for PMC drier.
27 */
28
29#include <sys/scsi/adapters/pmcs/pmcs.h>
30
31static void
32SATAcopy(pmcs_cmd_t *sp, void *kbuf, uint32_t amt)
33{
34	struct buf *bp = scsi_pkt2bp(CMD2PKT(sp));
35
36	bp_mapin(scsi_pkt2bp(CMD2PKT(sp)));
37	/* There is only one direction currently */
38	(void) memcpy(bp->b_un.b_addr, kbuf, amt);
39	CMD2PKT(sp)->pkt_resid -= amt;
40	CMD2PKT(sp)->pkt_state |= STATE_XFERRED_DATA;
41	bp_mapout(scsi_pkt2bp(CMD2PKT(sp)));
42}
43
44/*
45 * Run a non block-io command. Some commands are interpreted
46 * out of extant data. Some imply actually running a SATA command.
47 *
48 * Returns zero if we were able to run.
49 *
50 * Returns -1 only if other commands are active, either another
51 * command here or regular I/O active.
52 *
53 * Called with PHY lock and xp statlock held.
54 */
55#define	SRESPSZ	128
56
57static int
58pmcs_sata_special_work(pmcs_hw_t *pwp, pmcs_xscsi_t *xp)
59{
60	int i;
61	int saq;
62	pmcs_cmd_t *sp;
63	struct scsi_pkt *pkt;
64	pmcs_phy_t *pptr;
65	uint8_t rp[SRESPSZ];
66	ata_identify_t *id;
67	uint32_t amt = 0;
68	uint8_t key = 0x05;	/* illegal command */
69	uint8_t asc = 0;
70	uint8_t ascq = 0;
71	uint8_t status = STATUS_GOOD;
72
73	if (xp->actv_cnt) {
74		pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, xp,
75		    "%s: target %p actv count %u",
76		    __func__, (void *)xp, xp->actv_cnt);
77		return (-1);
78	}
79	if (xp->special_running) {
80		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp,
81		    "%s: target %p special running already",
82		    __func__, (void *)xp);
83		return (-1);
84	}
85	xp->special_needed = 0;
86
87	/*
88	 * We're now running special.
89	 */
90	xp->special_running = 1;
91	pptr = xp->phy;
92
93	sp = STAILQ_FIRST(&xp->sq);
94	if (sp == NULL) {
95		xp->special_running = 0;
96		return (0);
97	}
98
99	pkt = CMD2PKT(sp);
100	pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
101	    "%s: target %p cmd %p cdb0 %x with actv_cnt %u",
102	    __func__, (void *)xp, (void *)sp, pkt->pkt_cdbp[0], xp->actv_cnt);
103
104	if (pkt->pkt_cdbp[0] == SCMD_INQUIRY ||
105	    pkt->pkt_cdbp[0] == SCMD_READ_CAPACITY) {
106		int retval;
107
108		if (pmcs_acquire_scratch(pwp, B_FALSE)) {
109			xp->special_running = 0;
110			return (-1);
111		}
112		saq = 1;
113
114		mutex_exit(&xp->statlock);
115		retval = pmcs_sata_identify(pwp, pptr);
116		mutex_enter(&xp->statlock);
117
118		if (retval) {
119			pmcs_release_scratch(pwp);
120			xp->special_running = 0;
121
122			pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
123			    "%s: target %p identify failed %x",
124			    __func__, (void *)xp, retval);
125			/*
126			 * If the failure is due to not being
127			 * able to get resources, return such
128			 * that we'll try later. Otherwise,
129			 * fail current command.
130			 */
131			if (retval == ENOMEM) {
132				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
133				    "%s: sata identify failed (ENOMEM) for "
134				    "cmd %p", __func__, (void *)sp);
135				return (-1);
136			}
137			pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
138			    STATE_SENT_CMD;
139			if (retval == ETIMEDOUT) {
140				pkt->pkt_reason = CMD_TIMEOUT;
141				pkt->pkt_statistics |= STAT_TIMEOUT;
142			} else {
143				pkt->pkt_reason = CMD_TRAN_ERR;
144			}
145			goto out;
146		}
147
148		id = pwp->scratch;
149
150		/*
151		 * Check to see if this device is an NCQ capable device.
152		 * Yes, we'll end up doing this check for every INQUIRY
153		 * if indeed we *are* only a pio device, but this is so
154		 * infrequent that it's not really worth an extra bitfield.
155		 *
156		 * Note that PIO mode here means that the PMCS firmware
157		 * performs PIO- not us.
158		 */
159		if (xp->ncq == 0) {
160			/*
161			 * Reset existing stuff.
162			 */
163			xp->pio = 0;
164			xp->qdepth = 1;
165			xp->tagmap = 0;
166
167			if (id->word76 != 0 && id->word76 != 0xffff &&
168			    (LE_16(id->word76) & (1 << 8))) {
169				xp->ncq = 1;
170				xp->qdepth = (LE_16(id->word75) & 0x1f) + 1;
171				pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, xp,
172				    "%s: device %s supports NCQ %u deep",
173				    __func__, xp->phy->path, xp->qdepth);
174			} else {
175				/*
176				 * Default back to PIO.
177				 *
178				 * Note that non-FPDMA would still be possible,
179				 * but for this specific configuration, if it's
180				 * not NCQ it's safest to assume PIO.
181				 */
182				xp->pio = 1;
183				pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, xp,
184				    "%s: device %s assumed PIO",
185				    __func__, xp->phy->path);
186			}
187		}
188	} else {
189		saq = 0;
190		id = NULL;
191	}
192
193	bzero(rp, SRESPSZ);
194
195	switch (pkt->pkt_cdbp[0]) {
196	case SCMD_INQUIRY:
197	{
198		struct scsi_inquiry *inqp;
199		uint16_t *a, *b;
200
201		/* Check for illegal bits */
202		if ((pkt->pkt_cdbp[1] & 0xfc) || pkt->pkt_cdbp[5]) {
203			status = STATUS_CHECK;
204			asc = 0x24;	/* invalid field in cdb */
205			break;
206		}
207		if (pkt->pkt_cdbp[1] & 0x1) {
208			switch (pkt->pkt_cdbp[2]) {
209			case 0x0:
210				rp[3] = 3;
211				rp[5] = 0x80;
212				rp[6] = 0x83;
213				amt = 7;
214				break;
215			case 0x80:
216				rp[1] = 0x80;
217				rp[3] = 0x14;
218				a = (void *) &rp[4];
219				b = id->model_number;
220				for (i = 0; i < 5; i++) {
221					*a = ddi_swap16(*b);
222					a++;
223					b++;
224				}
225				amt = 24;
226				break;
227			case 0x83:
228				rp[1] = 0x83;
229				if ((LE_16(id->word87) & 0x100) &&
230				    (LE_16(id->word108) >> 12) == 5)  {
231					rp[3] = 12;
232					rp[4] = 1;
233					rp[5] = 3;
234					rp[7] = 8;
235					rp[8] = LE_16(id->word108) >> 8;
236					rp[9] = LE_16(id->word108);
237					rp[10] = LE_16(id->word109) >> 8;
238					rp[11] = LE_16(id->word109);
239					rp[12] = LE_16(id->word110) >> 8;
240					rp[13] = LE_16(id->word110);
241					rp[14] = LE_16(id->word111) >> 8;
242					rp[15] = LE_16(id->word111);
243					amt = 16;
244				} else {
245					rp[3] = 64;
246					rp[4] = 2;
247					rp[5] = 1;
248					rp[7] = 60;
249					rp[8] = 'A';
250					rp[9] = 'T';
251					rp[10] = 'A';
252					rp[11] = ' ';
253					rp[12] = ' ';
254					rp[13] = ' ';
255					rp[14] = ' ';
256					rp[15] = ' ';
257					a = (void *) &rp[16];
258					b = id->model_number;
259					for (i = 0; i < 20; i++) {
260						*a = ddi_swap16(*b);
261						a++;
262						b++;
263					}
264					a = (void *) &rp[40];
265					b = id->serial_number;
266					for (i = 0; i < 10; i++) {
267						*a = ddi_swap16(*b);
268						a++;
269						b++;
270					}
271					amt = 68;
272				}
273				break;
274			default:
275				status = STATUS_CHECK;
276				asc = 0x24;	/* invalid field in cdb */
277				break;
278			}
279		} else {
280			inqp = (struct scsi_inquiry *)rp;
281			inqp->inq_qual = (LE_16(id->word0) & 0x80) ? 0x80 : 0;
282			inqp->inq_ansi = 5;	/* spc3 */
283			inqp->inq_rdf = 2;	/* response format 2 */
284			inqp->inq_len = 32;
285
286			if (xp->ncq && (xp->qdepth > 1)) {
287				inqp->inq_cmdque = 1;
288			}
289
290			(void) memcpy(inqp->inq_vid, "ATA     ", 8);
291
292			a = (void *)inqp->inq_pid;
293			b = id->model_number;
294			for (i = 0; i < 8; i++) {
295				*a = ddi_swap16(*b);
296				a++;
297				b++;
298			}
299			if (id->firmware_revision[2] == 0x2020 &&
300			    id->firmware_revision[3] == 0x2020) {
301				inqp->inq_revision[0] =
302				    ddi_swap16(id->firmware_revision[0]) >> 8;
303				inqp->inq_revision[1] =
304				    ddi_swap16(id->firmware_revision[0]);
305				inqp->inq_revision[2] =
306				    ddi_swap16(id->firmware_revision[1]) >> 8;
307				inqp->inq_revision[3] =
308				    ddi_swap16(id->firmware_revision[1]);
309			} else {
310				inqp->inq_revision[0] =
311				    ddi_swap16(id->firmware_revision[2]) >> 8;
312				inqp->inq_revision[1] =
313				    ddi_swap16(id->firmware_revision[2]);
314				inqp->inq_revision[2] =
315				    ddi_swap16(id->firmware_revision[3]) >> 8;
316				inqp->inq_revision[3] =
317				    ddi_swap16(id->firmware_revision[3]);
318			}
319			amt = 36;
320		}
321		amt = pmcs_set_resid(pkt, amt, pkt->pkt_cdbp[4]);
322		if (amt) {
323			if (xp->actv_cnt) {
324				xp->special_needed = 1;
325				xp->special_running = 0;
326				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
327				    "%s: @ line %d", __func__, __LINE__);
328				if (saq) {
329					pmcs_release_scratch(pwp);
330				}
331				return (-1);
332			}
333			SATAcopy(sp, rp, amt);
334		}
335		break;
336	}
337	case SCMD_READ_CAPACITY:
338	{
339		uint64_t last_block;
340		uint32_t block_size = 512;	/* XXXX */
341
342		xp->capacity = LBA_CAPACITY(id);
343		last_block = xp->capacity - 1;
344		/* Check for illegal bits */
345		if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[6] ||
346		    (pkt->pkt_cdbp[8] & 0xfe) || pkt->pkt_cdbp[7] ||
347		    pkt->pkt_cdbp[9]) {
348			status = STATUS_CHECK;
349			asc = 0x24;	/* invalid field in cdb */
350			break;
351		}
352		for (i = 1; i < 10; i++) {
353			if (pkt->pkt_cdbp[i]) {
354				status = STATUS_CHECK;
355				asc = 0x24;	/* invalid field in cdb */
356				break;
357			}
358		}
359		if (status != STATUS_GOOD) {
360			break;
361		}
362		if (last_block > 0xffffffffULL) {
363			last_block = 0xffffffffULL;
364		}
365		rp[0] = (last_block >> 24) & 0xff;
366		rp[1] = (last_block >> 16) & 0xff;
367		rp[2] = (last_block >>  8) & 0xff;
368		rp[3] = (last_block) & 0xff;
369		rp[4] = (block_size >> 24) & 0xff;
370		rp[5] = (block_size >> 16) & 0xff;
371		rp[6] = (block_size >>  8) & 0xff;
372		rp[7] = (block_size) & 0xff;
373		amt = 8;
374		amt = pmcs_set_resid(pkt, amt, 8);
375		if (amt) {
376			if (xp->actv_cnt) {
377				xp->special_needed = 1;
378				xp->special_running = 0;
379				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
380				    "%s: @ line %d", __func__, __LINE__);
381				if (saq) {
382					pmcs_release_scratch(pwp);
383				}
384				return (-1);
385			}
386			SATAcopy(sp, rp, amt);
387		}
388		break;
389	}
390	case SCMD_REPORT_LUNS: {
391		int rl_len;
392
393		/* Check for illegal bits */
394		if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[3] || pkt->pkt_cdbp[4] ||
395		    pkt->pkt_cdbp[5] || pkt->pkt_cdbp[10] ||
396		    pkt->pkt_cdbp[11]) {
397			status = STATUS_CHECK;
398			asc = 0x24;	/* invalid field in cdb */
399			break;
400		}
401
402		rp[3] = 8;
403		rl_len = 16;	/* list length (4) + reserved (4) + 1 LUN (8) */
404		amt = rl_len;
405		amt = pmcs_set_resid(pkt, amt, rl_len);
406
407		if (amt) {
408			if (xp->actv_cnt) {
409				xp->special_needed = 1;
410				xp->special_running = 0;
411				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
412				    "%s: @ line %d", __func__, __LINE__);
413				if (saq) {
414					pmcs_release_scratch(pwp);
415				}
416				return (-1);
417			}
418			SATAcopy(sp, rp, rl_len);
419		}
420		break;
421	}
422
423	case SCMD_REQUEST_SENSE:
424		/* Check for illegal bits */
425		if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[2] ||
426		    pkt->pkt_cdbp[3] || pkt->pkt_cdbp[5]) {
427			status = STATUS_CHECK;
428			asc = 0x24;	/* invalid field in cdb */
429			break;
430		}
431		rp[0] = 0xf0;
432		amt = 18;
433		amt = pmcs_set_resid(pkt, amt, pkt->pkt_cdbp[4]);
434		if (amt) {
435			if (xp->actv_cnt) {
436				xp->special_needed = 1;
437				xp->special_running = 0;
438				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
439				    "%s: @ line %d", __func__, __LINE__);
440				if (saq) {
441					pmcs_release_scratch(pwp);
442				}
443				return (-1);
444			}
445			SATAcopy(sp, rp, 18);
446		}
447		break;
448	case SCMD_START_STOP:
449		/* Check for illegal bits */
450		if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[2] ||
451		    (pkt->pkt_cdbp[3] & 0xf0) || (pkt->pkt_cdbp[4] & 0x08) ||
452		    pkt->pkt_cdbp[5]) {
453			status = STATUS_CHECK;
454			asc = 0x24;	/* invalid field in cdb */
455			break;
456		}
457		break;
458	case SCMD_SYNCHRONIZE_CACHE:
459		/* Check for illegal bits */
460		if ((pkt->pkt_cdbp[1] & 0xf8) || (pkt->pkt_cdbp[6] & 0xe0) ||
461		    pkt->pkt_cdbp[9]) {
462			status = STATUS_CHECK;
463			asc = 0x24;	/* invalid field in cdb */
464			break;
465		}
466		break;
467	case SCMD_TEST_UNIT_READY:
468		/* Check for illegal bits */
469		if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[2] || pkt->pkt_cdbp[3] ||
470		    pkt->pkt_cdbp[4] || pkt->pkt_cdbp[5]) {
471			status = STATUS_CHECK;
472			asc = 0x24;	/* invalid field in cdb */
473			break;
474		}
475		if (xp->ca) {
476			status = STATUS_CHECK;
477			key = 0x6;
478			asc = 0x28;
479			xp->ca = 0;
480		}
481		break;
482	default:
483		asc = 0x20;	/* invalid operation command code */
484		status = STATUS_CHECK;
485		break;
486	}
487	if (status != STATUS_GOOD) {
488		bzero(rp, 18);
489		rp[0] = 0xf0;
490		rp[2] = key;
491		rp[12] = asc;
492		rp[13] = ascq;
493		pmcs_latch_status(pwp, sp, status, rp, 18, pptr->path);
494	} else {
495		pmcs_latch_status(pwp, sp, status, NULL, 0, pptr->path);
496	}
497
498out:
499	STAILQ_REMOVE_HEAD(&xp->sq, cmd_next);
500	pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
501	    "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x",
502	    __func__, (void *)pkt, xp->target_num, pkt->pkt_reason,
503	    pkt->pkt_state, pkt->pkt_resid, status);
504
505	if (saq) {
506		pmcs_release_scratch(pwp);
507	}
508
509	if (xp->draining) {
510		pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
511		    "%s: waking up drain waiters", __func__);
512		cv_signal(&pwp->drain_cv);
513	}
514
515	mutex_exit(&xp->statlock);
516	mutex_enter(&pwp->cq_lock);
517	STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next);
518	PMCS_CQ_RUN_LOCKED(pwp);
519	mutex_exit(&pwp->cq_lock);
520	mutex_enter(&xp->statlock);
521	xp->special_running = 0;
522	return (0);
523}
524
525/*
526 * Run all special commands queued up for a SATA device.
527 * We're only called if the caller knows we have work to do.
528 *
529 * We can't run them if things are still active for the device,
530 * return saying we didn't run anything.
531 *
532 * When we finish, wake up anyone waiting for active commands
533 * to go to zero.
534 *
535 * Called with PHY lock and xp statlock held.
536 */
537int
538pmcs_run_sata_special(pmcs_hw_t *pwp, pmcs_xscsi_t *xp)
539{
540	while (!STAILQ_EMPTY(&xp->sq)) {
541		if (pmcs_sata_special_work(pwp, xp)) {
542			return (-1);
543		}
544	}
545	return (0);
546}
547
548/*
549 * Search for SATA special commands to run and run them.
550 * If we succeed in running the special command(s), kick
551 * the normal commands into operation again. Call completion
552 * for any commands that were completed while we were here.
553 *
554 * Called unlocked.
555 */
556void
557pmcs_sata_work(pmcs_hw_t *pwp)
558{
559	pmcs_xscsi_t *xp;
560	int spinagain = 0;
561	uint16_t target;
562
563	for (target = 0; target < pwp->max_dev; target++) {
564		xp = pwp->targets[target];
565		if ((xp == NULL) || (xp->phy == NULL)) {
566			continue;
567		}
568		pmcs_lock_phy(xp->phy);
569		mutex_enter(&xp->statlock);
570		if (STAILQ_EMPTY(&xp->sq)) {
571			mutex_exit(&xp->statlock);
572			pmcs_unlock_phy(xp->phy);
573			continue;
574		}
575		if (xp->actv_cnt) {
576			xp->special_needed = 1;
577			pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, xp,
578			    "%s: deferring until drained", __func__);
579			spinagain++;
580		} else {
581			if (pmcs_run_sata_special(pwp, xp)) {
582				spinagain++;
583			}
584		}
585		mutex_exit(&xp->statlock);
586		pmcs_unlock_phy(xp->phy);
587	}
588
589	if (spinagain) {
590		SCHEDULE_WORK(pwp, PMCS_WORK_SATA_RUN);
591	} else {
592		SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES);
593	}
594
595	/*
596	 * Run completion on any commands ready for it.
597	 */
598	PMCS_CQ_RUN(pwp);
599}
600
601/*
602 * Called with PHY lock held and scratch acquired
603 */
604int
605pmcs_sata_identify(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
606{
607	fis_t fis;
608	fis[0] = (IDENTIFY_DEVICE << 16) | (1 << 15) | FIS_REG_H2DEV;
609	fis[1] = 0;
610	fis[2] = 0;
611	fis[3] = 0;
612	fis[4] = 0;
613	return (pmcs_run_sata_cmd(pwp, pptr, fis, SATA_PROTOCOL_PIO,
614	    PMCIN_DATADIR_2_INI, sizeof (ata_identify_t)));
615}
616
617/*
618 * Called with PHY lock held and scratch held
619 */
620int
621pmcs_run_sata_cmd(pmcs_hw_t *pwp, pmcs_phy_t *pptr, fis_t fis, uint32_t mode,
622    uint32_t ddir, uint32_t dlen)
623{
624	struct pmcwork *pwrk;
625	uint32_t *ptr, msg[PMCS_MSG_SIZE];
626	uint32_t iq, htag;
627	int i, result = 0;
628
629	pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, pptr);
630	if (pwrk == NULL) {
631		return (ENOMEM);
632	}
633
634	msg[0] = LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE,
635	    PMCIN_SATA_HOST_IO_START));
636	htag = pwrk->htag;
637	pwrk->arg = msg;
638	pwrk->dtype = SATA;
639	msg[1] = LE_32(pwrk->htag);
640	msg[2] = LE_32(pptr->device_id);
641	msg[3] = LE_32(dlen);
642	msg[4] = LE_32(mode | ddir);
643	if (dlen) {
644		if (ddir == PMCIN_DATADIR_2_DEV) {
645			if (ddi_dma_sync(pwp->cip_handles, 0, 0,
646			    DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {
647				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
648				    "Condition check failed at %s():%d",
649				    __func__, __LINE__);
650			}
651		}
652		msg[12] = LE_32(DWORD0(pwp->scratch_dma));
653		msg[13] = LE_32(DWORD1(pwp->scratch_dma));
654		msg[14] = LE_32(dlen);
655		msg[15] = 0;
656	} else {
657		msg[12] = 0;
658		msg[13] = 0;
659		msg[14] = 0;
660		msg[15] = 0;
661	}
662	for (i = 0; i < 5; i++) {
663		msg[5+i] = LE_32(fis[i]);
664	}
665	msg[10] = 0;
666	msg[11] = 0;
667	GET_IO_IQ_ENTRY(pwp, ptr, pptr->device_id, iq);
668	if (ptr == NULL) {
669		pmcs_pwork(pwp, pwrk);
670		return (ENOMEM);
671	}
672	COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE);
673	pwrk->state = PMCS_WORK_STATE_ONCHIP;
674	INC_IQ_ENTRY(pwp, iq);
675
676	pmcs_unlock_phy(pptr);
677	WAIT_FOR(pwrk, 1000, result);
678	pmcs_pwork(pwp, pwrk);
679	pmcs_lock_phy(pptr);
680
681	if (result) {
682		pmcs_timed_out(pwp, htag, __func__);
683		if (pmcs_abort(pwp, pptr, htag, 0, 1)) {
684			pptr->abort_pending = 1;
685			SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE);
686		}
687		return (ETIMEDOUT);
688	}
689
690	if (LE_32(msg[2]) != PMCOUT_STATUS_OK) {
691		return (EIO);
692	}
693	if (LE_32(ptr[3]) != 0) {
694		size_t j, amt = LE_32(ptr[3]);
695		if (amt > sizeof (fis_t)) {
696			amt = sizeof (fis_t);
697		}
698		amt >>= 2;
699		for (j = 0; j < amt; j++) {
700			fis[j] = LE_32(msg[4 + j]);
701		}
702	}
703	if (dlen && ddir == PMCIN_DATADIR_2_INI) {
704		if (ddi_dma_sync(pwp->cip_handles, 0, 0,
705		    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
706			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
707			    "Condition check failed at %s():%d",
708			    __func__, __LINE__);
709		}
710	}
711	return (0);
712}
713