110696SDavid.Hollister@Sun.COM /*
210696SDavid.Hollister@Sun.COM * CDDL HEADER START
310696SDavid.Hollister@Sun.COM *
410696SDavid.Hollister@Sun.COM * The contents of this file are subject to the terms of the
510696SDavid.Hollister@Sun.COM * Common Development and Distribution License (the "License").
610696SDavid.Hollister@Sun.COM * You may not use this file except in compliance with the License.
710696SDavid.Hollister@Sun.COM *
810696SDavid.Hollister@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910696SDavid.Hollister@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010696SDavid.Hollister@Sun.COM * See the License for the specific language governing permissions
1110696SDavid.Hollister@Sun.COM * and limitations under the License.
1210696SDavid.Hollister@Sun.COM *
1310696SDavid.Hollister@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410696SDavid.Hollister@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510696SDavid.Hollister@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610696SDavid.Hollister@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710696SDavid.Hollister@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810696SDavid.Hollister@Sun.COM *
1910696SDavid.Hollister@Sun.COM * CDDL HEADER END
2010696SDavid.Hollister@Sun.COM *
2110696SDavid.Hollister@Sun.COM *
2210696SDavid.Hollister@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2310696SDavid.Hollister@Sun.COM * Use is subject to license terms.
2410696SDavid.Hollister@Sun.COM */
2510696SDavid.Hollister@Sun.COM /*
2610696SDavid.Hollister@Sun.COM * SATA midlayer interface for PMC drier.
2710696SDavid.Hollister@Sun.COM */
2810696SDavid.Hollister@Sun.COM
2910696SDavid.Hollister@Sun.COM #include <sys/scsi/adapters/pmcs/pmcs.h>
3010696SDavid.Hollister@Sun.COM
3110696SDavid.Hollister@Sun.COM static void
SATAcopy(pmcs_cmd_t * sp,void * kbuf,uint32_t amt)3210696SDavid.Hollister@Sun.COM SATAcopy(pmcs_cmd_t *sp, void *kbuf, uint32_t amt)
3310696SDavid.Hollister@Sun.COM {
3410696SDavid.Hollister@Sun.COM struct buf *bp = scsi_pkt2bp(CMD2PKT(sp));
3510696SDavid.Hollister@Sun.COM
3610696SDavid.Hollister@Sun.COM bp_mapin(scsi_pkt2bp(CMD2PKT(sp)));
3710696SDavid.Hollister@Sun.COM /* There is only one direction currently */
3810696SDavid.Hollister@Sun.COM (void) memcpy(bp->b_un.b_addr, kbuf, amt);
3910696SDavid.Hollister@Sun.COM CMD2PKT(sp)->pkt_resid -= amt;
4010696SDavid.Hollister@Sun.COM CMD2PKT(sp)->pkt_state |= STATE_XFERRED_DATA;
4110696SDavid.Hollister@Sun.COM bp_mapout(scsi_pkt2bp(CMD2PKT(sp)));
4210696SDavid.Hollister@Sun.COM }
4310696SDavid.Hollister@Sun.COM
4410696SDavid.Hollister@Sun.COM /*
4510696SDavid.Hollister@Sun.COM * Run a non block-io command. Some commands are interpreted
4610696SDavid.Hollister@Sun.COM * out of extant data. Some imply actually running a SATA command.
4710696SDavid.Hollister@Sun.COM *
4810696SDavid.Hollister@Sun.COM * Returns zero if we were able to run.
4910696SDavid.Hollister@Sun.COM *
5010696SDavid.Hollister@Sun.COM * Returns -1 only if other commands are active, either another
5110696SDavid.Hollister@Sun.COM * command here or regular I/O active.
5210696SDavid.Hollister@Sun.COM *
5310696SDavid.Hollister@Sun.COM * Called with PHY lock and xp statlock held.
5410696SDavid.Hollister@Sun.COM */
5510696SDavid.Hollister@Sun.COM #define SRESPSZ 128
5610696SDavid.Hollister@Sun.COM
5710696SDavid.Hollister@Sun.COM static int
pmcs_sata_special_work(pmcs_hw_t * pwp,pmcs_xscsi_t * xp)5810696SDavid.Hollister@Sun.COM pmcs_sata_special_work(pmcs_hw_t *pwp, pmcs_xscsi_t *xp)
5910696SDavid.Hollister@Sun.COM {
6010696SDavid.Hollister@Sun.COM int i;
6110696SDavid.Hollister@Sun.COM int saq;
6210696SDavid.Hollister@Sun.COM pmcs_cmd_t *sp;
6310696SDavid.Hollister@Sun.COM struct scsi_pkt *pkt;
6410696SDavid.Hollister@Sun.COM pmcs_phy_t *pptr;
6510696SDavid.Hollister@Sun.COM uint8_t rp[SRESPSZ];
6610696SDavid.Hollister@Sun.COM ata_identify_t *id;
6710696SDavid.Hollister@Sun.COM uint32_t amt = 0;
6810696SDavid.Hollister@Sun.COM uint8_t key = 0x05; /* illegal command */
6910696SDavid.Hollister@Sun.COM uint8_t asc = 0;
7010696SDavid.Hollister@Sun.COM uint8_t ascq = 0;
7110696SDavid.Hollister@Sun.COM uint8_t status = STATUS_GOOD;
7210696SDavid.Hollister@Sun.COM
7310696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
7411048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, xp,
7511048SDavid.Hollister@Sun.COM "%s: target %p actv count %u",
7610696SDavid.Hollister@Sun.COM __func__, (void *)xp, xp->actv_cnt);
7710696SDavid.Hollister@Sun.COM return (-1);
7810696SDavid.Hollister@Sun.COM }
7910696SDavid.Hollister@Sun.COM if (xp->special_running) {
8011048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp,
8110696SDavid.Hollister@Sun.COM "%s: target %p special running already",
8210696SDavid.Hollister@Sun.COM __func__, (void *)xp);
8310696SDavid.Hollister@Sun.COM return (-1);
8410696SDavid.Hollister@Sun.COM }
8510696SDavid.Hollister@Sun.COM xp->special_needed = 0;
8610696SDavid.Hollister@Sun.COM
8710696SDavid.Hollister@Sun.COM /*
8810696SDavid.Hollister@Sun.COM * We're now running special.
8910696SDavid.Hollister@Sun.COM */
9010696SDavid.Hollister@Sun.COM xp->special_running = 1;
9110696SDavid.Hollister@Sun.COM pptr = xp->phy;
9210696SDavid.Hollister@Sun.COM
9310696SDavid.Hollister@Sun.COM sp = STAILQ_FIRST(&xp->sq);
9410696SDavid.Hollister@Sun.COM if (sp == NULL) {
9510696SDavid.Hollister@Sun.COM xp->special_running = 0;
9610696SDavid.Hollister@Sun.COM return (0);
9710696SDavid.Hollister@Sun.COM }
9810696SDavid.Hollister@Sun.COM
9910696SDavid.Hollister@Sun.COM pkt = CMD2PKT(sp);
10011048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
10110696SDavid.Hollister@Sun.COM "%s: target %p cmd %p cdb0 %x with actv_cnt %u",
10210696SDavid.Hollister@Sun.COM __func__, (void *)xp, (void *)sp, pkt->pkt_cdbp[0], xp->actv_cnt);
10310696SDavid.Hollister@Sun.COM
10410696SDavid.Hollister@Sun.COM if (pkt->pkt_cdbp[0] == SCMD_INQUIRY ||
10510696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[0] == SCMD_READ_CAPACITY) {
10610696SDavid.Hollister@Sun.COM int retval;
10710696SDavid.Hollister@Sun.COM
10810696SDavid.Hollister@Sun.COM if (pmcs_acquire_scratch(pwp, B_FALSE)) {
10910696SDavid.Hollister@Sun.COM xp->special_running = 0;
11010696SDavid.Hollister@Sun.COM return (-1);
11110696SDavid.Hollister@Sun.COM }
11210696SDavid.Hollister@Sun.COM saq = 1;
11310696SDavid.Hollister@Sun.COM
11410696SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
11510696SDavid.Hollister@Sun.COM retval = pmcs_sata_identify(pwp, pptr);
11610696SDavid.Hollister@Sun.COM mutex_enter(&xp->statlock);
11710696SDavid.Hollister@Sun.COM
11810696SDavid.Hollister@Sun.COM if (retval) {
11910696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
12010696SDavid.Hollister@Sun.COM xp->special_running = 0;
12110696SDavid.Hollister@Sun.COM
12211048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
12310696SDavid.Hollister@Sun.COM "%s: target %p identify failed %x",
12410696SDavid.Hollister@Sun.COM __func__, (void *)xp, retval);
12510696SDavid.Hollister@Sun.COM /*
12610696SDavid.Hollister@Sun.COM * If the failure is due to not being
12710696SDavid.Hollister@Sun.COM * able to get resources, return such
12810696SDavid.Hollister@Sun.COM * that we'll try later. Otherwise,
12910696SDavid.Hollister@Sun.COM * fail current command.
13010696SDavid.Hollister@Sun.COM */
13110696SDavid.Hollister@Sun.COM if (retval == ENOMEM) {
13211048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
13310696SDavid.Hollister@Sun.COM "%s: sata identify failed (ENOMEM) for "
13410696SDavid.Hollister@Sun.COM "cmd %p", __func__, (void *)sp);
13510696SDavid.Hollister@Sun.COM return (-1);
13610696SDavid.Hollister@Sun.COM }
13710696SDavid.Hollister@Sun.COM pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
13810696SDavid.Hollister@Sun.COM STATE_SENT_CMD;
13910696SDavid.Hollister@Sun.COM if (retval == ETIMEDOUT) {
14010696SDavid.Hollister@Sun.COM pkt->pkt_reason = CMD_TIMEOUT;
14110696SDavid.Hollister@Sun.COM pkt->pkt_statistics |= STAT_TIMEOUT;
14210696SDavid.Hollister@Sun.COM } else {
14310696SDavid.Hollister@Sun.COM pkt->pkt_reason = CMD_TRAN_ERR;
14410696SDavid.Hollister@Sun.COM }
14510696SDavid.Hollister@Sun.COM goto out;
14610696SDavid.Hollister@Sun.COM }
14710696SDavid.Hollister@Sun.COM
14810696SDavid.Hollister@Sun.COM id = pwp->scratch;
14910696SDavid.Hollister@Sun.COM
15010696SDavid.Hollister@Sun.COM /*
15110696SDavid.Hollister@Sun.COM * Check to see if this device is an NCQ capable device.
15210696SDavid.Hollister@Sun.COM * Yes, we'll end up doing this check for every INQUIRY
15310696SDavid.Hollister@Sun.COM * if indeed we *are* only a pio device, but this is so
15410696SDavid.Hollister@Sun.COM * infrequent that it's not really worth an extra bitfield.
15510696SDavid.Hollister@Sun.COM *
15610696SDavid.Hollister@Sun.COM * Note that PIO mode here means that the PMCS firmware
15710696SDavid.Hollister@Sun.COM * performs PIO- not us.
15810696SDavid.Hollister@Sun.COM */
15910696SDavid.Hollister@Sun.COM if (xp->ncq == 0) {
16010696SDavid.Hollister@Sun.COM /*
16110696SDavid.Hollister@Sun.COM * Reset existing stuff.
16210696SDavid.Hollister@Sun.COM */
16310696SDavid.Hollister@Sun.COM xp->pio = 0;
16410696SDavid.Hollister@Sun.COM xp->qdepth = 1;
16510696SDavid.Hollister@Sun.COM xp->tagmap = 0;
16610696SDavid.Hollister@Sun.COM
16710696SDavid.Hollister@Sun.COM if (id->word76 != 0 && id->word76 != 0xffff &&
16810696SDavid.Hollister@Sun.COM (LE_16(id->word76) & (1 << 8))) {
16910696SDavid.Hollister@Sun.COM xp->ncq = 1;
17010696SDavid.Hollister@Sun.COM xp->qdepth = (LE_16(id->word75) & 0x1f) + 1;
17111048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, xp,
17210696SDavid.Hollister@Sun.COM "%s: device %s supports NCQ %u deep",
17310696SDavid.Hollister@Sun.COM __func__, xp->phy->path, xp->qdepth);
17410696SDavid.Hollister@Sun.COM } else {
17510696SDavid.Hollister@Sun.COM /*
17610696SDavid.Hollister@Sun.COM * Default back to PIO.
17710696SDavid.Hollister@Sun.COM *
17810696SDavid.Hollister@Sun.COM * Note that non-FPDMA would still be possible,
17910696SDavid.Hollister@Sun.COM * but for this specific configuration, if it's
18010696SDavid.Hollister@Sun.COM * not NCQ it's safest to assume PIO.
18110696SDavid.Hollister@Sun.COM */
18210696SDavid.Hollister@Sun.COM xp->pio = 1;
18311048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, xp,
18410696SDavid.Hollister@Sun.COM "%s: device %s assumed PIO",
18510696SDavid.Hollister@Sun.COM __func__, xp->phy->path);
18610696SDavid.Hollister@Sun.COM }
18710696SDavid.Hollister@Sun.COM }
18810696SDavid.Hollister@Sun.COM } else {
18910696SDavid.Hollister@Sun.COM saq = 0;
19010696SDavid.Hollister@Sun.COM id = NULL;
19110696SDavid.Hollister@Sun.COM }
19210696SDavid.Hollister@Sun.COM
19310696SDavid.Hollister@Sun.COM bzero(rp, SRESPSZ);
19410696SDavid.Hollister@Sun.COM
19510696SDavid.Hollister@Sun.COM switch (pkt->pkt_cdbp[0]) {
19610696SDavid.Hollister@Sun.COM case SCMD_INQUIRY:
19710696SDavid.Hollister@Sun.COM {
19810696SDavid.Hollister@Sun.COM struct scsi_inquiry *inqp;
19910696SDavid.Hollister@Sun.COM uint16_t *a, *b;
20010696SDavid.Hollister@Sun.COM
20110696SDavid.Hollister@Sun.COM /* Check for illegal bits */
20210696SDavid.Hollister@Sun.COM if ((pkt->pkt_cdbp[1] & 0xfc) || pkt->pkt_cdbp[5]) {
20310696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
20410696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
20510696SDavid.Hollister@Sun.COM break;
20610696SDavid.Hollister@Sun.COM }
20710696SDavid.Hollister@Sun.COM if (pkt->pkt_cdbp[1] & 0x1) {
20810696SDavid.Hollister@Sun.COM switch (pkt->pkt_cdbp[2]) {
20910696SDavid.Hollister@Sun.COM case 0x0:
21010696SDavid.Hollister@Sun.COM rp[3] = 3;
21110696SDavid.Hollister@Sun.COM rp[5] = 0x80;
21210696SDavid.Hollister@Sun.COM rp[6] = 0x83;
21310696SDavid.Hollister@Sun.COM amt = 7;
21410696SDavid.Hollister@Sun.COM break;
21510696SDavid.Hollister@Sun.COM case 0x80:
21610696SDavid.Hollister@Sun.COM rp[1] = 0x80;
21710696SDavid.Hollister@Sun.COM rp[3] = 0x14;
21810696SDavid.Hollister@Sun.COM a = (void *) &rp[4];
21910696SDavid.Hollister@Sun.COM b = id->model_number;
22010696SDavid.Hollister@Sun.COM for (i = 0; i < 5; i++) {
22110696SDavid.Hollister@Sun.COM *a = ddi_swap16(*b);
22210696SDavid.Hollister@Sun.COM a++;
22310696SDavid.Hollister@Sun.COM b++;
22410696SDavid.Hollister@Sun.COM }
22510696SDavid.Hollister@Sun.COM amt = 24;
22610696SDavid.Hollister@Sun.COM break;
22710696SDavid.Hollister@Sun.COM case 0x83:
22810696SDavid.Hollister@Sun.COM rp[1] = 0x83;
22910696SDavid.Hollister@Sun.COM if ((LE_16(id->word87) & 0x100) &&
23010696SDavid.Hollister@Sun.COM (LE_16(id->word108) >> 12) == 5) {
23110696SDavid.Hollister@Sun.COM rp[3] = 12;
23210696SDavid.Hollister@Sun.COM rp[4] = 1;
23310696SDavid.Hollister@Sun.COM rp[5] = 3;
23410696SDavid.Hollister@Sun.COM rp[7] = 8;
23510696SDavid.Hollister@Sun.COM rp[8] = LE_16(id->word108) >> 8;
23610696SDavid.Hollister@Sun.COM rp[9] = LE_16(id->word108);
23710696SDavid.Hollister@Sun.COM rp[10] = LE_16(id->word109) >> 8;
23810696SDavid.Hollister@Sun.COM rp[11] = LE_16(id->word109);
23910696SDavid.Hollister@Sun.COM rp[12] = LE_16(id->word110) >> 8;
24010696SDavid.Hollister@Sun.COM rp[13] = LE_16(id->word110);
24110696SDavid.Hollister@Sun.COM rp[14] = LE_16(id->word111) >> 8;
24210696SDavid.Hollister@Sun.COM rp[15] = LE_16(id->word111);
24310696SDavid.Hollister@Sun.COM amt = 16;
24410696SDavid.Hollister@Sun.COM } else {
24510696SDavid.Hollister@Sun.COM rp[3] = 64;
24610696SDavid.Hollister@Sun.COM rp[4] = 2;
24710696SDavid.Hollister@Sun.COM rp[5] = 1;
24810696SDavid.Hollister@Sun.COM rp[7] = 60;
24910696SDavid.Hollister@Sun.COM rp[8] = 'A';
25010696SDavid.Hollister@Sun.COM rp[9] = 'T';
25110696SDavid.Hollister@Sun.COM rp[10] = 'A';
25210696SDavid.Hollister@Sun.COM rp[11] = ' ';
25310696SDavid.Hollister@Sun.COM rp[12] = ' ';
25410696SDavid.Hollister@Sun.COM rp[13] = ' ';
25510696SDavid.Hollister@Sun.COM rp[14] = ' ';
25610696SDavid.Hollister@Sun.COM rp[15] = ' ';
25710696SDavid.Hollister@Sun.COM a = (void *) &rp[16];
25810696SDavid.Hollister@Sun.COM b = id->model_number;
25910696SDavid.Hollister@Sun.COM for (i = 0; i < 20; i++) {
26010696SDavid.Hollister@Sun.COM *a = ddi_swap16(*b);
26110696SDavid.Hollister@Sun.COM a++;
26210696SDavid.Hollister@Sun.COM b++;
26310696SDavid.Hollister@Sun.COM }
26410696SDavid.Hollister@Sun.COM a = (void *) &rp[40];
26510696SDavid.Hollister@Sun.COM b = id->serial_number;
26610696SDavid.Hollister@Sun.COM for (i = 0; i < 10; i++) {
26710696SDavid.Hollister@Sun.COM *a = ddi_swap16(*b);
26810696SDavid.Hollister@Sun.COM a++;
26910696SDavid.Hollister@Sun.COM b++;
27010696SDavid.Hollister@Sun.COM }
27110696SDavid.Hollister@Sun.COM amt = 68;
27210696SDavid.Hollister@Sun.COM }
27310696SDavid.Hollister@Sun.COM break;
27410696SDavid.Hollister@Sun.COM default:
27510696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
27610696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
27710696SDavid.Hollister@Sun.COM break;
27810696SDavid.Hollister@Sun.COM }
27910696SDavid.Hollister@Sun.COM } else {
28010696SDavid.Hollister@Sun.COM inqp = (struct scsi_inquiry *)rp;
28110696SDavid.Hollister@Sun.COM inqp->inq_qual = (LE_16(id->word0) & 0x80) ? 0x80 : 0;
28210696SDavid.Hollister@Sun.COM inqp->inq_ansi = 5; /* spc3 */
28310696SDavid.Hollister@Sun.COM inqp->inq_rdf = 2; /* response format 2 */
28410696SDavid.Hollister@Sun.COM inqp->inq_len = 32;
28510696SDavid.Hollister@Sun.COM
28610696SDavid.Hollister@Sun.COM if (xp->ncq && (xp->qdepth > 1)) {
28710696SDavid.Hollister@Sun.COM inqp->inq_cmdque = 1;
28810696SDavid.Hollister@Sun.COM }
28910696SDavid.Hollister@Sun.COM
29010696SDavid.Hollister@Sun.COM (void) memcpy(inqp->inq_vid, "ATA ", 8);
29110696SDavid.Hollister@Sun.COM
29210696SDavid.Hollister@Sun.COM a = (void *)inqp->inq_pid;
29310696SDavid.Hollister@Sun.COM b = id->model_number;
29410696SDavid.Hollister@Sun.COM for (i = 0; i < 8; i++) {
29510696SDavid.Hollister@Sun.COM *a = ddi_swap16(*b);
29610696SDavid.Hollister@Sun.COM a++;
29710696SDavid.Hollister@Sun.COM b++;
29810696SDavid.Hollister@Sun.COM }
29910696SDavid.Hollister@Sun.COM if (id->firmware_revision[2] == 0x2020 &&
30010696SDavid.Hollister@Sun.COM id->firmware_revision[3] == 0x2020) {
30110696SDavid.Hollister@Sun.COM inqp->inq_revision[0] =
30210696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[0]) >> 8;
30310696SDavid.Hollister@Sun.COM inqp->inq_revision[1] =
30410696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[0]);
30510696SDavid.Hollister@Sun.COM inqp->inq_revision[2] =
30610696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[1]) >> 8;
30710696SDavid.Hollister@Sun.COM inqp->inq_revision[3] =
30810696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[1]);
30910696SDavid.Hollister@Sun.COM } else {
31010696SDavid.Hollister@Sun.COM inqp->inq_revision[0] =
31110696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[2]) >> 8;
31210696SDavid.Hollister@Sun.COM inqp->inq_revision[1] =
31310696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[2]);
31410696SDavid.Hollister@Sun.COM inqp->inq_revision[2] =
31510696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[3]) >> 8;
31610696SDavid.Hollister@Sun.COM inqp->inq_revision[3] =
31710696SDavid.Hollister@Sun.COM ddi_swap16(id->firmware_revision[3]);
31810696SDavid.Hollister@Sun.COM }
31910696SDavid.Hollister@Sun.COM amt = 36;
32010696SDavid.Hollister@Sun.COM }
32110696SDavid.Hollister@Sun.COM amt = pmcs_set_resid(pkt, amt, pkt->pkt_cdbp[4]);
32210696SDavid.Hollister@Sun.COM if (amt) {
32310696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
32410696SDavid.Hollister@Sun.COM xp->special_needed = 1;
32510696SDavid.Hollister@Sun.COM xp->special_running = 0;
32611048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
32711048SDavid.Hollister@Sun.COM "%s: @ line %d", __func__, __LINE__);
32810696SDavid.Hollister@Sun.COM if (saq) {
32910696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
33010696SDavid.Hollister@Sun.COM }
33110696SDavid.Hollister@Sun.COM return (-1);
33210696SDavid.Hollister@Sun.COM }
33310696SDavid.Hollister@Sun.COM SATAcopy(sp, rp, amt);
33410696SDavid.Hollister@Sun.COM }
33510696SDavid.Hollister@Sun.COM break;
33610696SDavid.Hollister@Sun.COM }
33710696SDavid.Hollister@Sun.COM case SCMD_READ_CAPACITY:
33810696SDavid.Hollister@Sun.COM {
33910696SDavid.Hollister@Sun.COM uint64_t last_block;
34010696SDavid.Hollister@Sun.COM uint32_t block_size = 512; /* XXXX */
34110696SDavid.Hollister@Sun.COM
34210696SDavid.Hollister@Sun.COM xp->capacity = LBA_CAPACITY(id);
34310696SDavid.Hollister@Sun.COM last_block = xp->capacity - 1;
34410696SDavid.Hollister@Sun.COM /* Check for illegal bits */
34510696SDavid.Hollister@Sun.COM if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[6] ||
34610696SDavid.Hollister@Sun.COM (pkt->pkt_cdbp[8] & 0xfe) || pkt->pkt_cdbp[7] ||
34710696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[9]) {
34810696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
34910696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
35010696SDavid.Hollister@Sun.COM break;
35110696SDavid.Hollister@Sun.COM }
35210696SDavid.Hollister@Sun.COM for (i = 1; i < 10; i++) {
35310696SDavid.Hollister@Sun.COM if (pkt->pkt_cdbp[i]) {
35410696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
35510696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
35610696SDavid.Hollister@Sun.COM break;
35710696SDavid.Hollister@Sun.COM }
35810696SDavid.Hollister@Sun.COM }
35910696SDavid.Hollister@Sun.COM if (status != STATUS_GOOD) {
36010696SDavid.Hollister@Sun.COM break;
36110696SDavid.Hollister@Sun.COM }
36210696SDavid.Hollister@Sun.COM if (last_block > 0xffffffffULL) {
36310696SDavid.Hollister@Sun.COM last_block = 0xffffffffULL;
36410696SDavid.Hollister@Sun.COM }
36510696SDavid.Hollister@Sun.COM rp[0] = (last_block >> 24) & 0xff;
36610696SDavid.Hollister@Sun.COM rp[1] = (last_block >> 16) & 0xff;
36710696SDavid.Hollister@Sun.COM rp[2] = (last_block >> 8) & 0xff;
36810696SDavid.Hollister@Sun.COM rp[3] = (last_block) & 0xff;
36910696SDavid.Hollister@Sun.COM rp[4] = (block_size >> 24) & 0xff;
37010696SDavid.Hollister@Sun.COM rp[5] = (block_size >> 16) & 0xff;
37110696SDavid.Hollister@Sun.COM rp[6] = (block_size >> 8) & 0xff;
37210696SDavid.Hollister@Sun.COM rp[7] = (block_size) & 0xff;
37310696SDavid.Hollister@Sun.COM amt = 8;
37410696SDavid.Hollister@Sun.COM amt = pmcs_set_resid(pkt, amt, 8);
37510696SDavid.Hollister@Sun.COM if (amt) {
37610696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
37710696SDavid.Hollister@Sun.COM xp->special_needed = 1;
37810696SDavid.Hollister@Sun.COM xp->special_running = 0;
37911048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
38011048SDavid.Hollister@Sun.COM "%s: @ line %d", __func__, __LINE__);
38110696SDavid.Hollister@Sun.COM if (saq) {
38210696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
38310696SDavid.Hollister@Sun.COM }
38410696SDavid.Hollister@Sun.COM return (-1);
38510696SDavid.Hollister@Sun.COM }
38610696SDavid.Hollister@Sun.COM SATAcopy(sp, rp, amt);
38710696SDavid.Hollister@Sun.COM }
38810696SDavid.Hollister@Sun.COM break;
38910696SDavid.Hollister@Sun.COM }
39010696SDavid.Hollister@Sun.COM case SCMD_REPORT_LUNS: {
39110696SDavid.Hollister@Sun.COM int rl_len;
39210696SDavid.Hollister@Sun.COM
39310696SDavid.Hollister@Sun.COM /* Check for illegal bits */
39410696SDavid.Hollister@Sun.COM if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[3] || pkt->pkt_cdbp[4] ||
39510696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[5] || pkt->pkt_cdbp[10] ||
39610696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[11]) {
39710696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
39810696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
39910696SDavid.Hollister@Sun.COM break;
40010696SDavid.Hollister@Sun.COM }
40110696SDavid.Hollister@Sun.COM
40210696SDavid.Hollister@Sun.COM rp[3] = 8;
40310696SDavid.Hollister@Sun.COM rl_len = 16; /* list length (4) + reserved (4) + 1 LUN (8) */
40410696SDavid.Hollister@Sun.COM amt = rl_len;
40510696SDavid.Hollister@Sun.COM amt = pmcs_set_resid(pkt, amt, rl_len);
40610696SDavid.Hollister@Sun.COM
40710696SDavid.Hollister@Sun.COM if (amt) {
40810696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
40910696SDavid.Hollister@Sun.COM xp->special_needed = 1;
41010696SDavid.Hollister@Sun.COM xp->special_running = 0;
41111048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
41211048SDavid.Hollister@Sun.COM "%s: @ line %d", __func__, __LINE__);
41310696SDavid.Hollister@Sun.COM if (saq) {
41410696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
41510696SDavid.Hollister@Sun.COM }
41610696SDavid.Hollister@Sun.COM return (-1);
41710696SDavid.Hollister@Sun.COM }
41810696SDavid.Hollister@Sun.COM SATAcopy(sp, rp, rl_len);
41910696SDavid.Hollister@Sun.COM }
42010696SDavid.Hollister@Sun.COM break;
42110696SDavid.Hollister@Sun.COM }
42210696SDavid.Hollister@Sun.COM
42310696SDavid.Hollister@Sun.COM case SCMD_REQUEST_SENSE:
42410696SDavid.Hollister@Sun.COM /* Check for illegal bits */
42510696SDavid.Hollister@Sun.COM if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[2] ||
42610696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[3] || pkt->pkt_cdbp[5]) {
42710696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
42810696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
42910696SDavid.Hollister@Sun.COM break;
43010696SDavid.Hollister@Sun.COM }
43110696SDavid.Hollister@Sun.COM rp[0] = 0xf0;
43210696SDavid.Hollister@Sun.COM amt = 18;
43310696SDavid.Hollister@Sun.COM amt = pmcs_set_resid(pkt, amt, pkt->pkt_cdbp[4]);
43410696SDavid.Hollister@Sun.COM if (amt) {
43510696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
43610696SDavid.Hollister@Sun.COM xp->special_needed = 1;
43710696SDavid.Hollister@Sun.COM xp->special_running = 0;
43811048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
43911048SDavid.Hollister@Sun.COM "%s: @ line %d", __func__, __LINE__);
44010696SDavid.Hollister@Sun.COM if (saq) {
44110696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
44210696SDavid.Hollister@Sun.COM }
44310696SDavid.Hollister@Sun.COM return (-1);
44410696SDavid.Hollister@Sun.COM }
44510696SDavid.Hollister@Sun.COM SATAcopy(sp, rp, 18);
44610696SDavid.Hollister@Sun.COM }
44710696SDavid.Hollister@Sun.COM break;
44810696SDavid.Hollister@Sun.COM case SCMD_START_STOP:
44910696SDavid.Hollister@Sun.COM /* Check for illegal bits */
45010696SDavid.Hollister@Sun.COM if ((pkt->pkt_cdbp[1] & 0xfe) || pkt->pkt_cdbp[2] ||
45110696SDavid.Hollister@Sun.COM (pkt->pkt_cdbp[3] & 0xf0) || (pkt->pkt_cdbp[4] & 0x08) ||
45210696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[5]) {
45310696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
45410696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
45510696SDavid.Hollister@Sun.COM break;
45610696SDavid.Hollister@Sun.COM }
45710696SDavid.Hollister@Sun.COM break;
45810696SDavid.Hollister@Sun.COM case SCMD_SYNCHRONIZE_CACHE:
45910696SDavid.Hollister@Sun.COM /* Check for illegal bits */
46010696SDavid.Hollister@Sun.COM if ((pkt->pkt_cdbp[1] & 0xf8) || (pkt->pkt_cdbp[6] & 0xe0) ||
46110696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[9]) {
46210696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
46310696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
46410696SDavid.Hollister@Sun.COM break;
46510696SDavid.Hollister@Sun.COM }
46610696SDavid.Hollister@Sun.COM break;
46710696SDavid.Hollister@Sun.COM case SCMD_TEST_UNIT_READY:
46810696SDavid.Hollister@Sun.COM /* Check for illegal bits */
46910696SDavid.Hollister@Sun.COM if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[2] || pkt->pkt_cdbp[3] ||
47010696SDavid.Hollister@Sun.COM pkt->pkt_cdbp[4] || pkt->pkt_cdbp[5]) {
47110696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
47210696SDavid.Hollister@Sun.COM asc = 0x24; /* invalid field in cdb */
47310696SDavid.Hollister@Sun.COM break;
47410696SDavid.Hollister@Sun.COM }
47510696SDavid.Hollister@Sun.COM if (xp->ca) {
47610696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
47710696SDavid.Hollister@Sun.COM key = 0x6;
47810696SDavid.Hollister@Sun.COM asc = 0x28;
47910696SDavid.Hollister@Sun.COM xp->ca = 0;
48010696SDavid.Hollister@Sun.COM }
48110696SDavid.Hollister@Sun.COM break;
48210696SDavid.Hollister@Sun.COM default:
48310696SDavid.Hollister@Sun.COM asc = 0x20; /* invalid operation command code */
48410696SDavid.Hollister@Sun.COM status = STATUS_CHECK;
48510696SDavid.Hollister@Sun.COM break;
48610696SDavid.Hollister@Sun.COM }
48710696SDavid.Hollister@Sun.COM if (status != STATUS_GOOD) {
48810696SDavid.Hollister@Sun.COM bzero(rp, 18);
48910696SDavid.Hollister@Sun.COM rp[0] = 0xf0;
49010696SDavid.Hollister@Sun.COM rp[2] = key;
49110696SDavid.Hollister@Sun.COM rp[12] = asc;
49210696SDavid.Hollister@Sun.COM rp[13] = ascq;
49310696SDavid.Hollister@Sun.COM pmcs_latch_status(pwp, sp, status, rp, 18, pptr->path);
49410696SDavid.Hollister@Sun.COM } else {
49510696SDavid.Hollister@Sun.COM pmcs_latch_status(pwp, sp, status, NULL, 0, pptr->path);
49610696SDavid.Hollister@Sun.COM }
49710696SDavid.Hollister@Sun.COM
49810696SDavid.Hollister@Sun.COM out:
49910696SDavid.Hollister@Sun.COM STAILQ_REMOVE_HEAD(&xp->sq, cmd_next);
50011048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp,
50110696SDavid.Hollister@Sun.COM "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x",
50210696SDavid.Hollister@Sun.COM __func__, (void *)pkt, xp->target_num, pkt->pkt_reason,
50310696SDavid.Hollister@Sun.COM pkt->pkt_state, pkt->pkt_resid, status);
50410696SDavid.Hollister@Sun.COM
50510696SDavid.Hollister@Sun.COM if (saq) {
50610696SDavid.Hollister@Sun.COM pmcs_release_scratch(pwp);
50710696SDavid.Hollister@Sun.COM }
50810696SDavid.Hollister@Sun.COM
50910696SDavid.Hollister@Sun.COM if (xp->draining) {
51011048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp,
51110696SDavid.Hollister@Sun.COM "%s: waking up drain waiters", __func__);
51210696SDavid.Hollister@Sun.COM cv_signal(&pwp->drain_cv);
51310696SDavid.Hollister@Sun.COM }
51410696SDavid.Hollister@Sun.COM
51510696SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
51610696SDavid.Hollister@Sun.COM mutex_enter(&pwp->cq_lock);
51710696SDavid.Hollister@Sun.COM STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next);
51810696SDavid.Hollister@Sun.COM PMCS_CQ_RUN_LOCKED(pwp);
51910696SDavid.Hollister@Sun.COM mutex_exit(&pwp->cq_lock);
52010696SDavid.Hollister@Sun.COM mutex_enter(&xp->statlock);
52110696SDavid.Hollister@Sun.COM xp->special_running = 0;
52210696SDavid.Hollister@Sun.COM return (0);
52310696SDavid.Hollister@Sun.COM }
52410696SDavid.Hollister@Sun.COM
52510696SDavid.Hollister@Sun.COM /*
52610696SDavid.Hollister@Sun.COM * Run all special commands queued up for a SATA device.
52710696SDavid.Hollister@Sun.COM * We're only called if the caller knows we have work to do.
52810696SDavid.Hollister@Sun.COM *
52910696SDavid.Hollister@Sun.COM * We can't run them if things are still active for the device,
53010696SDavid.Hollister@Sun.COM * return saying we didn't run anything.
53110696SDavid.Hollister@Sun.COM *
53210696SDavid.Hollister@Sun.COM * When we finish, wake up anyone waiting for active commands
53310696SDavid.Hollister@Sun.COM * to go to zero.
53410696SDavid.Hollister@Sun.COM *
53510696SDavid.Hollister@Sun.COM * Called with PHY lock and xp statlock held.
53610696SDavid.Hollister@Sun.COM */
53710696SDavid.Hollister@Sun.COM int
pmcs_run_sata_special(pmcs_hw_t * pwp,pmcs_xscsi_t * xp)53810696SDavid.Hollister@Sun.COM pmcs_run_sata_special(pmcs_hw_t *pwp, pmcs_xscsi_t *xp)
53910696SDavid.Hollister@Sun.COM {
54010696SDavid.Hollister@Sun.COM while (!STAILQ_EMPTY(&xp->sq)) {
54110696SDavid.Hollister@Sun.COM if (pmcs_sata_special_work(pwp, xp)) {
54210696SDavid.Hollister@Sun.COM return (-1);
54310696SDavid.Hollister@Sun.COM }
54410696SDavid.Hollister@Sun.COM }
54510696SDavid.Hollister@Sun.COM return (0);
54610696SDavid.Hollister@Sun.COM }
54710696SDavid.Hollister@Sun.COM
54810696SDavid.Hollister@Sun.COM /*
54910696SDavid.Hollister@Sun.COM * Search for SATA special commands to run and run them.
55010696SDavid.Hollister@Sun.COM * If we succeed in running the special command(s), kick
55110696SDavid.Hollister@Sun.COM * the normal commands into operation again. Call completion
55210696SDavid.Hollister@Sun.COM * for any commands that were completed while we were here.
55310696SDavid.Hollister@Sun.COM *
55410696SDavid.Hollister@Sun.COM * Called unlocked.
55510696SDavid.Hollister@Sun.COM */
55610696SDavid.Hollister@Sun.COM void
pmcs_sata_work(pmcs_hw_t * pwp)55710696SDavid.Hollister@Sun.COM pmcs_sata_work(pmcs_hw_t *pwp)
55810696SDavid.Hollister@Sun.COM {
55910696SDavid.Hollister@Sun.COM pmcs_xscsi_t *xp;
56010696SDavid.Hollister@Sun.COM int spinagain = 0;
56110696SDavid.Hollister@Sun.COM uint16_t target;
56210696SDavid.Hollister@Sun.COM
56310696SDavid.Hollister@Sun.COM for (target = 0; target < pwp->max_dev; target++) {
56410696SDavid.Hollister@Sun.COM xp = pwp->targets[target];
56510696SDavid.Hollister@Sun.COM if ((xp == NULL) || (xp->phy == NULL)) {
56610696SDavid.Hollister@Sun.COM continue;
56710696SDavid.Hollister@Sun.COM }
56810696SDavid.Hollister@Sun.COM pmcs_lock_phy(xp->phy);
56910696SDavid.Hollister@Sun.COM mutex_enter(&xp->statlock);
57010696SDavid.Hollister@Sun.COM if (STAILQ_EMPTY(&xp->sq)) {
57110696SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
57210696SDavid.Hollister@Sun.COM pmcs_unlock_phy(xp->phy);
57310696SDavid.Hollister@Sun.COM continue;
57410696SDavid.Hollister@Sun.COM }
57510696SDavid.Hollister@Sun.COM if (xp->actv_cnt) {
57610696SDavid.Hollister@Sun.COM xp->special_needed = 1;
57711048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, xp,
57810696SDavid.Hollister@Sun.COM "%s: deferring until drained", __func__);
57910696SDavid.Hollister@Sun.COM spinagain++;
58010696SDavid.Hollister@Sun.COM } else {
58110696SDavid.Hollister@Sun.COM if (pmcs_run_sata_special(pwp, xp)) {
58210696SDavid.Hollister@Sun.COM spinagain++;
58310696SDavid.Hollister@Sun.COM }
58410696SDavid.Hollister@Sun.COM }
58510696SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
58610696SDavid.Hollister@Sun.COM pmcs_unlock_phy(xp->phy);
58710696SDavid.Hollister@Sun.COM }
58810696SDavid.Hollister@Sun.COM
58910696SDavid.Hollister@Sun.COM if (spinagain) {
59010696SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_SATA_RUN);
59110696SDavid.Hollister@Sun.COM } else {
59210696SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES);
59310696SDavid.Hollister@Sun.COM }
59410696SDavid.Hollister@Sun.COM
59510696SDavid.Hollister@Sun.COM /*
59610696SDavid.Hollister@Sun.COM * Run completion on any commands ready for it.
59710696SDavid.Hollister@Sun.COM */
59810696SDavid.Hollister@Sun.COM PMCS_CQ_RUN(pwp);
59910696SDavid.Hollister@Sun.COM }
60010696SDavid.Hollister@Sun.COM
60110696SDavid.Hollister@Sun.COM /*
60210696SDavid.Hollister@Sun.COM * Called with PHY lock held and scratch acquired
60310696SDavid.Hollister@Sun.COM */
60410696SDavid.Hollister@Sun.COM int
pmcs_sata_identify(pmcs_hw_t * pwp,pmcs_phy_t * pptr)60510696SDavid.Hollister@Sun.COM pmcs_sata_identify(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
60610696SDavid.Hollister@Sun.COM {
60710696SDavid.Hollister@Sun.COM fis_t fis;
60810696SDavid.Hollister@Sun.COM fis[0] = (IDENTIFY_DEVICE << 16) | (1 << 15) | FIS_REG_H2DEV;
60910696SDavid.Hollister@Sun.COM fis[1] = 0;
61010696SDavid.Hollister@Sun.COM fis[2] = 0;
61110696SDavid.Hollister@Sun.COM fis[3] = 0;
61210696SDavid.Hollister@Sun.COM fis[4] = 0;
61310696SDavid.Hollister@Sun.COM return (pmcs_run_sata_cmd(pwp, pptr, fis, SATA_PROTOCOL_PIO,
61410696SDavid.Hollister@Sun.COM PMCIN_DATADIR_2_INI, sizeof (ata_identify_t)));
61510696SDavid.Hollister@Sun.COM }
61610696SDavid.Hollister@Sun.COM
61710696SDavid.Hollister@Sun.COM /*
61810696SDavid.Hollister@Sun.COM * Called with PHY lock held and scratch held
61910696SDavid.Hollister@Sun.COM */
62010696SDavid.Hollister@Sun.COM int
pmcs_run_sata_cmd(pmcs_hw_t * pwp,pmcs_phy_t * pptr,fis_t fis,uint32_t mode,uint32_t ddir,uint32_t dlen)62110696SDavid.Hollister@Sun.COM pmcs_run_sata_cmd(pmcs_hw_t *pwp, pmcs_phy_t *pptr, fis_t fis, uint32_t mode,
62210696SDavid.Hollister@Sun.COM uint32_t ddir, uint32_t dlen)
62310696SDavid.Hollister@Sun.COM {
62410696SDavid.Hollister@Sun.COM struct pmcwork *pwrk;
62510696SDavid.Hollister@Sun.COM uint32_t *ptr, msg[PMCS_MSG_SIZE];
626*11307SDavid.Hollister@Sun.COM uint32_t iq, htag, status;
62710696SDavid.Hollister@Sun.COM int i, result = 0;
62810696SDavid.Hollister@Sun.COM
62910696SDavid.Hollister@Sun.COM pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, pptr);
63010696SDavid.Hollister@Sun.COM if (pwrk == NULL) {
63110696SDavid.Hollister@Sun.COM return (ENOMEM);
63210696SDavid.Hollister@Sun.COM }
63310696SDavid.Hollister@Sun.COM
63410696SDavid.Hollister@Sun.COM msg[0] = LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE,
63510696SDavid.Hollister@Sun.COM PMCIN_SATA_HOST_IO_START));
63610696SDavid.Hollister@Sun.COM htag = pwrk->htag;
63710696SDavid.Hollister@Sun.COM pwrk->arg = msg;
63810696SDavid.Hollister@Sun.COM pwrk->dtype = SATA;
63910696SDavid.Hollister@Sun.COM msg[1] = LE_32(pwrk->htag);
64010696SDavid.Hollister@Sun.COM msg[2] = LE_32(pptr->device_id);
64110696SDavid.Hollister@Sun.COM msg[3] = LE_32(dlen);
64210696SDavid.Hollister@Sun.COM msg[4] = LE_32(mode | ddir);
64310696SDavid.Hollister@Sun.COM if (dlen) {
64410696SDavid.Hollister@Sun.COM if (ddir == PMCIN_DATADIR_2_DEV) {
64510696SDavid.Hollister@Sun.COM if (ddi_dma_sync(pwp->cip_handles, 0, 0,
64610696SDavid.Hollister@Sun.COM DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {
64711048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
64811048SDavid.Hollister@Sun.COM "Condition check failed at %s():%d",
64911048SDavid.Hollister@Sun.COM __func__, __LINE__);
65010696SDavid.Hollister@Sun.COM }
65110696SDavid.Hollister@Sun.COM }
65210696SDavid.Hollister@Sun.COM msg[12] = LE_32(DWORD0(pwp->scratch_dma));
65310696SDavid.Hollister@Sun.COM msg[13] = LE_32(DWORD1(pwp->scratch_dma));
65410696SDavid.Hollister@Sun.COM msg[14] = LE_32(dlen);
65510696SDavid.Hollister@Sun.COM msg[15] = 0;
65610696SDavid.Hollister@Sun.COM } else {
65710696SDavid.Hollister@Sun.COM msg[12] = 0;
65810696SDavid.Hollister@Sun.COM msg[13] = 0;
65910696SDavid.Hollister@Sun.COM msg[14] = 0;
66010696SDavid.Hollister@Sun.COM msg[15] = 0;
66110696SDavid.Hollister@Sun.COM }
66210696SDavid.Hollister@Sun.COM for (i = 0; i < 5; i++) {
66310696SDavid.Hollister@Sun.COM msg[5+i] = LE_32(fis[i]);
66410696SDavid.Hollister@Sun.COM }
66510696SDavid.Hollister@Sun.COM msg[10] = 0;
66610696SDavid.Hollister@Sun.COM msg[11] = 0;
66710696SDavid.Hollister@Sun.COM GET_IO_IQ_ENTRY(pwp, ptr, pptr->device_id, iq);
66810696SDavid.Hollister@Sun.COM if (ptr == NULL) {
66910696SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
67010696SDavid.Hollister@Sun.COM return (ENOMEM);
67110696SDavid.Hollister@Sun.COM }
67210696SDavid.Hollister@Sun.COM COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE);
67310696SDavid.Hollister@Sun.COM pwrk->state = PMCS_WORK_STATE_ONCHIP;
67410696SDavid.Hollister@Sun.COM INC_IQ_ENTRY(pwp, iq);
67510696SDavid.Hollister@Sun.COM
67610696SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
67710696SDavid.Hollister@Sun.COM WAIT_FOR(pwrk, 1000, result);
67810696SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
67910696SDavid.Hollister@Sun.COM pmcs_lock_phy(pptr);
68010696SDavid.Hollister@Sun.COM
68110696SDavid.Hollister@Sun.COM if (result) {
68210696SDavid.Hollister@Sun.COM pmcs_timed_out(pwp, htag, __func__);
68310696SDavid.Hollister@Sun.COM if (pmcs_abort(pwp, pptr, htag, 0, 1)) {
68410696SDavid.Hollister@Sun.COM pptr->abort_pending = 1;
68510696SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE);
68610696SDavid.Hollister@Sun.COM }
68710696SDavid.Hollister@Sun.COM return (ETIMEDOUT);
68810696SDavid.Hollister@Sun.COM }
68910696SDavid.Hollister@Sun.COM
690*11307SDavid.Hollister@Sun.COM status = LE_32(msg[2]);
691*11307SDavid.Hollister@Sun.COM
692*11307SDavid.Hollister@Sun.COM if (status != PMCOUT_STATUS_OK) {
693*11307SDavid.Hollister@Sun.COM if (status == PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY) {
694*11307SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, pptr->target,
695*11307SDavid.Hollister@Sun.COM "%s: Potential affiliation active on 0x%" PRIx64,
696*11307SDavid.Hollister@Sun.COM __func__, pmcs_barray2wwn(pptr->sas_address));
697*11307SDavid.Hollister@Sun.COM } else {
698*11307SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, pptr->target,
699*11307SDavid.Hollister@Sun.COM "%s: SATA I/O returned with IOMB status 0x%x",
700*11307SDavid.Hollister@Sun.COM __func__, status);
701*11307SDavid.Hollister@Sun.COM }
70210696SDavid.Hollister@Sun.COM return (EIO);
70310696SDavid.Hollister@Sun.COM }
704*11307SDavid.Hollister@Sun.COM
70510696SDavid.Hollister@Sun.COM if (LE_32(ptr[3]) != 0) {
70610696SDavid.Hollister@Sun.COM size_t j, amt = LE_32(ptr[3]);
70710696SDavid.Hollister@Sun.COM if (amt > sizeof (fis_t)) {
70810696SDavid.Hollister@Sun.COM amt = sizeof (fis_t);
70910696SDavid.Hollister@Sun.COM }
71010696SDavid.Hollister@Sun.COM amt >>= 2;
71110696SDavid.Hollister@Sun.COM for (j = 0; j < amt; j++) {
71210696SDavid.Hollister@Sun.COM fis[j] = LE_32(msg[4 + j]);
71310696SDavid.Hollister@Sun.COM }
71410696SDavid.Hollister@Sun.COM }
71510696SDavid.Hollister@Sun.COM if (dlen && ddir == PMCIN_DATADIR_2_INI) {
71610696SDavid.Hollister@Sun.COM if (ddi_dma_sync(pwp->cip_handles, 0, 0,
71710696SDavid.Hollister@Sun.COM DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
71811048SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
71911048SDavid.Hollister@Sun.COM "Condition check failed at %s():%d",
72011048SDavid.Hollister@Sun.COM __func__, __LINE__);
72110696SDavid.Hollister@Sun.COM }
72210696SDavid.Hollister@Sun.COM }
72310696SDavid.Hollister@Sun.COM return (0);
72410696SDavid.Hollister@Sun.COM }
725