1*338ec570SDarrick J. Wong /* 2*338ec570SDarrick J. Wong * Support for SATA devices on Serial Attached SCSI (SAS) controllers 3*338ec570SDarrick J. Wong * 4*338ec570SDarrick J. Wong * Copyright (C) 2006 IBM Corporation 5*338ec570SDarrick J. Wong * 6*338ec570SDarrick J. Wong * Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM Corporation 7*338ec570SDarrick J. Wong * 8*338ec570SDarrick J. Wong * This program is free software; you can redistribute it and/or 9*338ec570SDarrick J. Wong * modify it under the terms of the GNU General Public License as 10*338ec570SDarrick J. Wong * published by the Free Software Foundation; either version 2 of the 11*338ec570SDarrick J. Wong * License, or (at your option) any later version. 12*338ec570SDarrick J. Wong * 13*338ec570SDarrick J. Wong * This program is distributed in the hope that it will be useful, but 14*338ec570SDarrick J. Wong * WITHOUT ANY WARRANTY; without even the implied warranty of 15*338ec570SDarrick J. Wong * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16*338ec570SDarrick J. Wong * General Public License for more details. 17*338ec570SDarrick J. Wong * 18*338ec570SDarrick J. Wong * You should have received a copy of the GNU General Public License 19*338ec570SDarrick J. Wong * along with this program; if not, write to the Free Software 20*338ec570SDarrick J. Wong * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 21*338ec570SDarrick J. Wong * USA 22*338ec570SDarrick J. Wong */ 23*338ec570SDarrick J. Wong 24*338ec570SDarrick J. Wong #include <scsi/sas_ata.h> 25*338ec570SDarrick J. Wong #include "sas_internal.h" 26*338ec570SDarrick J. Wong #include <scsi/scsi_host.h> 27*338ec570SDarrick J. Wong #include <scsi/scsi_device.h> 28*338ec570SDarrick J. Wong #include <scsi/scsi_tcq.h> 29*338ec570SDarrick J. Wong #include <scsi/scsi.h> 30*338ec570SDarrick J. Wong #include <scsi/scsi_transport.h> 31*338ec570SDarrick J. Wong #include <scsi/scsi_transport_sas.h> 32*338ec570SDarrick J. Wong #include "../scsi_sas_internal.h" 33*338ec570SDarrick J. Wong 34*338ec570SDarrick J. Wong static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) 35*338ec570SDarrick J. Wong { 36*338ec570SDarrick J. Wong /* Cheesy attempt to translate SAS errors into ATA. Hah! */ 37*338ec570SDarrick J. Wong 38*338ec570SDarrick J. Wong /* transport error */ 39*338ec570SDarrick J. Wong if (ts->resp == SAS_TASK_UNDELIVERED) 40*338ec570SDarrick J. Wong return AC_ERR_ATA_BUS; 41*338ec570SDarrick J. Wong 42*338ec570SDarrick J. Wong /* ts->resp == SAS_TASK_COMPLETE */ 43*338ec570SDarrick J. Wong /* task delivered, what happened afterwards? */ 44*338ec570SDarrick J. Wong switch (ts->stat) { 45*338ec570SDarrick J. Wong case SAS_DEV_NO_RESPONSE: 46*338ec570SDarrick J. Wong return AC_ERR_TIMEOUT; 47*338ec570SDarrick J. Wong 48*338ec570SDarrick J. Wong case SAS_INTERRUPTED: 49*338ec570SDarrick J. Wong case SAS_PHY_DOWN: 50*338ec570SDarrick J. Wong case SAS_NAK_R_ERR: 51*338ec570SDarrick J. Wong return AC_ERR_ATA_BUS; 52*338ec570SDarrick J. Wong 53*338ec570SDarrick J. Wong 54*338ec570SDarrick J. Wong case SAS_DATA_UNDERRUN: 55*338ec570SDarrick J. Wong /* 56*338ec570SDarrick J. Wong * Some programs that use the taskfile interface 57*338ec570SDarrick J. Wong * (smartctl in particular) can cause underrun 58*338ec570SDarrick J. Wong * problems. Ignore these errors, perhaps at our 59*338ec570SDarrick J. Wong * peril. 60*338ec570SDarrick J. Wong */ 61*338ec570SDarrick J. Wong return 0; 62*338ec570SDarrick J. Wong 63*338ec570SDarrick J. Wong case SAS_DATA_OVERRUN: 64*338ec570SDarrick J. Wong case SAS_QUEUE_FULL: 65*338ec570SDarrick J. Wong case SAS_DEVICE_UNKNOWN: 66*338ec570SDarrick J. Wong case SAS_SG_ERR: 67*338ec570SDarrick J. Wong return AC_ERR_INVALID; 68*338ec570SDarrick J. Wong 69*338ec570SDarrick J. Wong case SAM_CHECK_COND: 70*338ec570SDarrick J. Wong case SAS_OPEN_TO: 71*338ec570SDarrick J. Wong case SAS_OPEN_REJECT: 72*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Saw error %d. What to do?\n", 73*338ec570SDarrick J. Wong __FUNCTION__, ts->stat); 74*338ec570SDarrick J. Wong return AC_ERR_OTHER; 75*338ec570SDarrick J. Wong 76*338ec570SDarrick J. Wong case SAS_ABORTED_TASK: 77*338ec570SDarrick J. Wong return AC_ERR_DEV; 78*338ec570SDarrick J. Wong 79*338ec570SDarrick J. Wong case SAS_PROTO_RESPONSE: 80*338ec570SDarrick J. Wong /* This means the ending_fis has the error 81*338ec570SDarrick J. Wong * value; return 0 here to collect it */ 82*338ec570SDarrick J. Wong return 0; 83*338ec570SDarrick J. Wong default: 84*338ec570SDarrick J. Wong return 0; 85*338ec570SDarrick J. Wong } 86*338ec570SDarrick J. Wong } 87*338ec570SDarrick J. Wong 88*338ec570SDarrick J. Wong static void sas_ata_task_done(struct sas_task *task) 89*338ec570SDarrick J. Wong { 90*338ec570SDarrick J. Wong struct ata_queued_cmd *qc = task->uldd_task; 91*338ec570SDarrick J. Wong struct domain_device *dev = qc->ap->private_data; 92*338ec570SDarrick J. Wong struct task_status_struct *stat = &task->task_status; 93*338ec570SDarrick J. Wong struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf; 94*338ec570SDarrick J. Wong enum ata_completion_errors ac; 95*338ec570SDarrick J. Wong 96*338ec570SDarrick J. Wong if (stat->stat == SAS_PROTO_RESPONSE) { 97*338ec570SDarrick J. Wong ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); 98*338ec570SDarrick J. Wong qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); 99*338ec570SDarrick J. Wong dev->sata_dev.sstatus = resp->sstatus; 100*338ec570SDarrick J. Wong dev->sata_dev.serror = resp->serror; 101*338ec570SDarrick J. Wong dev->sata_dev.scontrol = resp->scontrol; 102*338ec570SDarrick J. Wong dev->sata_dev.ap->sactive = resp->sactive; 103*338ec570SDarrick J. Wong } else if (stat->stat != SAM_STAT_GOOD) { 104*338ec570SDarrick J. Wong ac = sas_to_ata_err(stat); 105*338ec570SDarrick J. Wong if (ac) { 106*338ec570SDarrick J. Wong SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__, 107*338ec570SDarrick J. Wong stat->stat); 108*338ec570SDarrick J. Wong /* We saw a SAS error. Send a vague error. */ 109*338ec570SDarrick J. Wong qc->err_mask = ac; 110*338ec570SDarrick J. Wong dev->sata_dev.tf.feature = 0x04; /* status err */ 111*338ec570SDarrick J. Wong dev->sata_dev.tf.command = ATA_ERR; 112*338ec570SDarrick J. Wong } 113*338ec570SDarrick J. Wong } 114*338ec570SDarrick J. Wong 115*338ec570SDarrick J. Wong ata_qc_complete(qc); 116*338ec570SDarrick J. Wong list_del_init(&task->list); 117*338ec570SDarrick J. Wong sas_free_task(task); 118*338ec570SDarrick J. Wong } 119*338ec570SDarrick J. Wong 120*338ec570SDarrick J. Wong static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) 121*338ec570SDarrick J. Wong { 122*338ec570SDarrick J. Wong int res = -ENOMEM; 123*338ec570SDarrick J. Wong struct sas_task *task; 124*338ec570SDarrick J. Wong struct domain_device *dev = qc->ap->private_data; 125*338ec570SDarrick J. Wong struct sas_ha_struct *sas_ha = dev->port->ha; 126*338ec570SDarrick J. Wong struct Scsi_Host *host = sas_ha->core.shost; 127*338ec570SDarrick J. Wong struct sas_internal *i = to_sas_internal(host->transportt); 128*338ec570SDarrick J. Wong struct scatterlist *sg; 129*338ec570SDarrick J. Wong unsigned int num = 0; 130*338ec570SDarrick J. Wong unsigned int xfer = 0; 131*338ec570SDarrick J. Wong 132*338ec570SDarrick J. Wong task = sas_alloc_task(GFP_ATOMIC); 133*338ec570SDarrick J. Wong if (!task) 134*338ec570SDarrick J. Wong goto out; 135*338ec570SDarrick J. Wong task->dev = dev; 136*338ec570SDarrick J. Wong task->task_proto = SAS_PROTOCOL_STP; 137*338ec570SDarrick J. Wong task->task_done = sas_ata_task_done; 138*338ec570SDarrick J. Wong 139*338ec570SDarrick J. Wong if (qc->tf.command == ATA_CMD_FPDMA_WRITE || 140*338ec570SDarrick J. Wong qc->tf.command == ATA_CMD_FPDMA_READ) { 141*338ec570SDarrick J. Wong /* Need to zero out the tag libata assigned us */ 142*338ec570SDarrick J. Wong qc->tf.nsect = 0; 143*338ec570SDarrick J. Wong } 144*338ec570SDarrick J. Wong 145*338ec570SDarrick J. Wong ata_tf_to_fis(&qc->tf, (u8*)&task->ata_task.fis, 0); 146*338ec570SDarrick J. Wong task->uldd_task = qc; 147*338ec570SDarrick J. Wong if (is_atapi_taskfile(&qc->tf)) { 148*338ec570SDarrick J. Wong memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); 149*338ec570SDarrick J. Wong task->total_xfer_len = qc->nbytes + qc->pad_len; 150*338ec570SDarrick J. Wong task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; 151*338ec570SDarrick J. Wong } else { 152*338ec570SDarrick J. Wong ata_for_each_sg(sg, qc) { 153*338ec570SDarrick J. Wong num++; 154*338ec570SDarrick J. Wong xfer += sg->length; 155*338ec570SDarrick J. Wong } 156*338ec570SDarrick J. Wong 157*338ec570SDarrick J. Wong task->total_xfer_len = xfer; 158*338ec570SDarrick J. Wong task->num_scatter = num; 159*338ec570SDarrick J. Wong } 160*338ec570SDarrick J. Wong 161*338ec570SDarrick J. Wong task->data_dir = qc->dma_dir; 162*338ec570SDarrick J. Wong task->scatter = qc->__sg; 163*338ec570SDarrick J. Wong task->ata_task.retry_count = 1; 164*338ec570SDarrick J. Wong task->task_state_flags = SAS_TASK_STATE_PENDING; 165*338ec570SDarrick J. Wong 166*338ec570SDarrick J. Wong switch (qc->tf.protocol) { 167*338ec570SDarrick J. Wong case ATA_PROT_NCQ: 168*338ec570SDarrick J. Wong task->ata_task.use_ncq = 1; 169*338ec570SDarrick J. Wong /* fall through */ 170*338ec570SDarrick J. Wong case ATA_PROT_ATAPI_DMA: 171*338ec570SDarrick J. Wong case ATA_PROT_DMA: 172*338ec570SDarrick J. Wong task->ata_task.dma_xfer = 1; 173*338ec570SDarrick J. Wong break; 174*338ec570SDarrick J. Wong } 175*338ec570SDarrick J. Wong 176*338ec570SDarrick J. Wong if (sas_ha->lldd_max_execute_num < 2) 177*338ec570SDarrick J. Wong res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); 178*338ec570SDarrick J. Wong else 179*338ec570SDarrick J. Wong res = sas_queue_up(task); 180*338ec570SDarrick J. Wong 181*338ec570SDarrick J. Wong /* Examine */ 182*338ec570SDarrick J. Wong if (res) { 183*338ec570SDarrick J. Wong SAS_DPRINTK("lldd_execute_task returned: %d\n", res); 184*338ec570SDarrick J. Wong 185*338ec570SDarrick J. Wong sas_free_task(task); 186*338ec570SDarrick J. Wong if (res == -SAS_QUEUE_FULL) 187*338ec570SDarrick J. Wong return -ENOMEM; 188*338ec570SDarrick J. Wong } 189*338ec570SDarrick J. Wong 190*338ec570SDarrick J. Wong out: 191*338ec570SDarrick J. Wong return res; 192*338ec570SDarrick J. Wong } 193*338ec570SDarrick J. Wong 194*338ec570SDarrick J. Wong static u8 sas_ata_check_status(struct ata_port *ap) 195*338ec570SDarrick J. Wong { 196*338ec570SDarrick J. Wong struct domain_device *dev = ap->private_data; 197*338ec570SDarrick J. Wong return dev->sata_dev.tf.command; 198*338ec570SDarrick J. Wong } 199*338ec570SDarrick J. Wong 200*338ec570SDarrick J. Wong static void sas_ata_phy_reset(struct ata_port *ap) 201*338ec570SDarrick J. Wong { 202*338ec570SDarrick J. Wong struct domain_device *dev = ap->private_data; 203*338ec570SDarrick J. Wong struct sas_internal *i = 204*338ec570SDarrick J. Wong to_sas_internal(dev->port->ha->core.shost->transportt); 205*338ec570SDarrick J. Wong int res = 0; 206*338ec570SDarrick J. Wong 207*338ec570SDarrick J. Wong if (i->dft->lldd_I_T_nexus_reset) 208*338ec570SDarrick J. Wong res = i->dft->lldd_I_T_nexus_reset(dev); 209*338ec570SDarrick J. Wong 210*338ec570SDarrick J. Wong if (res) 211*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__); 212*338ec570SDarrick J. Wong 213*338ec570SDarrick J. Wong switch (dev->sata_dev.command_set) { 214*338ec570SDarrick J. Wong case ATA_COMMAND_SET: 215*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); 216*338ec570SDarrick J. Wong ap->device[0].class = ATA_DEV_ATA; 217*338ec570SDarrick J. Wong break; 218*338ec570SDarrick J. Wong case ATAPI_COMMAND_SET: 219*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); 220*338ec570SDarrick J. Wong ap->device[0].class = ATA_DEV_ATAPI; 221*338ec570SDarrick J. Wong break; 222*338ec570SDarrick J. Wong default: 223*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", 224*338ec570SDarrick J. Wong __FUNCTION__, 225*338ec570SDarrick J. Wong dev->sata_dev.command_set); 226*338ec570SDarrick J. Wong ap->device[0].class = ATA_DEV_ATA; 227*338ec570SDarrick J. Wong break; 228*338ec570SDarrick J. Wong } 229*338ec570SDarrick J. Wong 230*338ec570SDarrick J. Wong ap->cbl = ATA_CBL_SATA; 231*338ec570SDarrick J. Wong } 232*338ec570SDarrick J. Wong 233*338ec570SDarrick J. Wong static void sas_ata_post_internal(struct ata_queued_cmd *qc) 234*338ec570SDarrick J. Wong { 235*338ec570SDarrick J. Wong if (qc->flags & ATA_QCFLAG_FAILED) 236*338ec570SDarrick J. Wong qc->err_mask |= AC_ERR_OTHER; 237*338ec570SDarrick J. Wong 238*338ec570SDarrick J. Wong if (qc->err_mask) 239*338ec570SDarrick J. Wong SAS_DPRINTK("%s: Failure; reset phy!\n", __FUNCTION__); 240*338ec570SDarrick J. Wong } 241*338ec570SDarrick J. Wong 242*338ec570SDarrick J. Wong static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 243*338ec570SDarrick J. Wong { 244*338ec570SDarrick J. Wong struct domain_device *dev = ap->private_data; 245*338ec570SDarrick J. Wong memcpy(tf, &dev->sata_dev.tf, sizeof (*tf)); 246*338ec570SDarrick J. Wong } 247*338ec570SDarrick J. Wong 248*338ec570SDarrick J. Wong static void sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, 249*338ec570SDarrick J. Wong u32 val) 250*338ec570SDarrick J. Wong { 251*338ec570SDarrick J. Wong struct domain_device *dev = ap->private_data; 252*338ec570SDarrick J. Wong 253*338ec570SDarrick J. Wong SAS_DPRINTK("STUB %s\n", __FUNCTION__); 254*338ec570SDarrick J. Wong switch (sc_reg_in) { 255*338ec570SDarrick J. Wong case SCR_STATUS: 256*338ec570SDarrick J. Wong dev->sata_dev.sstatus = val; 257*338ec570SDarrick J. Wong break; 258*338ec570SDarrick J. Wong case SCR_CONTROL: 259*338ec570SDarrick J. Wong dev->sata_dev.scontrol = val; 260*338ec570SDarrick J. Wong break; 261*338ec570SDarrick J. Wong case SCR_ERROR: 262*338ec570SDarrick J. Wong dev->sata_dev.serror = val; 263*338ec570SDarrick J. Wong break; 264*338ec570SDarrick J. Wong case SCR_ACTIVE: 265*338ec570SDarrick J. Wong dev->sata_dev.ap->sactive = val; 266*338ec570SDarrick J. Wong break; 267*338ec570SDarrick J. Wong } 268*338ec570SDarrick J. Wong } 269*338ec570SDarrick J. Wong 270*338ec570SDarrick J. Wong static u32 sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in) 271*338ec570SDarrick J. Wong { 272*338ec570SDarrick J. Wong struct domain_device *dev = ap->private_data; 273*338ec570SDarrick J. Wong 274*338ec570SDarrick J. Wong SAS_DPRINTK("STUB %s\n", __FUNCTION__); 275*338ec570SDarrick J. Wong switch (sc_reg_in) { 276*338ec570SDarrick J. Wong case SCR_STATUS: 277*338ec570SDarrick J. Wong return dev->sata_dev.sstatus; 278*338ec570SDarrick J. Wong case SCR_CONTROL: 279*338ec570SDarrick J. Wong return dev->sata_dev.scontrol; 280*338ec570SDarrick J. Wong case SCR_ERROR: 281*338ec570SDarrick J. Wong return dev->sata_dev.serror; 282*338ec570SDarrick J. Wong case SCR_ACTIVE: 283*338ec570SDarrick J. Wong return dev->sata_dev.ap->sactive; 284*338ec570SDarrick J. Wong default: 285*338ec570SDarrick J. Wong return 0xffffffffU; 286*338ec570SDarrick J. Wong } 287*338ec570SDarrick J. Wong } 288*338ec570SDarrick J. Wong 289*338ec570SDarrick J. Wong static struct ata_port_operations sas_sata_ops = { 290*338ec570SDarrick J. Wong .port_disable = ata_port_disable, 291*338ec570SDarrick J. Wong .check_status = sas_ata_check_status, 292*338ec570SDarrick J. Wong .check_altstatus = sas_ata_check_status, 293*338ec570SDarrick J. Wong .dev_select = ata_noop_dev_select, 294*338ec570SDarrick J. Wong .phy_reset = sas_ata_phy_reset, 295*338ec570SDarrick J. Wong .post_internal_cmd = sas_ata_post_internal, 296*338ec570SDarrick J. Wong .tf_read = sas_ata_tf_read, 297*338ec570SDarrick J. Wong .qc_prep = ata_noop_qc_prep, 298*338ec570SDarrick J. Wong .qc_issue = sas_ata_qc_issue, 299*338ec570SDarrick J. Wong .port_start = ata_sas_port_start, 300*338ec570SDarrick J. Wong .port_stop = ata_sas_port_stop, 301*338ec570SDarrick J. Wong .scr_read = sas_ata_scr_read, 302*338ec570SDarrick J. Wong .scr_write = sas_ata_scr_write 303*338ec570SDarrick J. Wong }; 304*338ec570SDarrick J. Wong 305*338ec570SDarrick J. Wong static struct ata_port_info sata_port_info = { 306*338ec570SDarrick J. Wong .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | 307*338ec570SDarrick J. Wong ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, 308*338ec570SDarrick J. Wong .pio_mask = 0x1f, /* PIO0-4 */ 309*338ec570SDarrick J. Wong .mwdma_mask = 0x07, /* MWDMA0-2 */ 310*338ec570SDarrick J. Wong .udma_mask = ATA_UDMA6, 311*338ec570SDarrick J. Wong .port_ops = &sas_sata_ops 312*338ec570SDarrick J. Wong }; 313*338ec570SDarrick J. Wong 314*338ec570SDarrick J. Wong int sas_ata_init_host_and_port(struct domain_device *found_dev, 315*338ec570SDarrick J. Wong struct scsi_target *starget) 316*338ec570SDarrick J. Wong { 317*338ec570SDarrick J. Wong struct Scsi_Host *shost = dev_to_shost(&starget->dev); 318*338ec570SDarrick J. Wong struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); 319*338ec570SDarrick J. Wong struct ata_port *ap; 320*338ec570SDarrick J. Wong 321*338ec570SDarrick J. Wong ata_host_init(&found_dev->sata_dev.ata_host, 322*338ec570SDarrick J. Wong &ha->pcidev->dev, 323*338ec570SDarrick J. Wong sata_port_info.flags, 324*338ec570SDarrick J. Wong &sas_sata_ops); 325*338ec570SDarrick J. Wong ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, 326*338ec570SDarrick J. Wong &sata_port_info, 327*338ec570SDarrick J. Wong shost); 328*338ec570SDarrick J. Wong if (!ap) { 329*338ec570SDarrick J. Wong SAS_DPRINTK("ata_sas_port_alloc failed.\n"); 330*338ec570SDarrick J. Wong return -ENODEV; 331*338ec570SDarrick J. Wong } 332*338ec570SDarrick J. Wong 333*338ec570SDarrick J. Wong ap->private_data = found_dev; 334*338ec570SDarrick J. Wong ap->cbl = ATA_CBL_SATA; 335*338ec570SDarrick J. Wong ap->scsi_host = shost; 336*338ec570SDarrick J. Wong found_dev->sata_dev.ap = ap; 337*338ec570SDarrick J. Wong 338*338ec570SDarrick J. Wong return 0; 339*338ec570SDarrick J. Wong } 340