162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell 88SE64xx/88SE94xx main function 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 662306a36Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 762306a36Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 862306a36Sopenharmony_ci*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mv_sas.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci if (task->lldd_task) { 1562306a36Sopenharmony_ci struct mvs_slot_info *slot; 1662306a36Sopenharmony_ci slot = task->lldd_task; 1762306a36Sopenharmony_ci *tag = slot->slot_tag; 1862306a36Sopenharmony_ci return 1; 1962306a36Sopenharmony_ci } 2062306a36Sopenharmony_ci return 0; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void mvs_tag_clear(struct mvs_info *mvi, u32 tag) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci void *bitmap = mvi->rsvd_tags; 2662306a36Sopenharmony_ci clear_bit(tag, bitmap); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void mvs_tag_free(struct mvs_info *mvi, u32 tag) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci if (tag >= MVS_RSVD_SLOTS) 3262306a36Sopenharmony_ci return; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci mvs_tag_clear(mvi, tag); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci void *bitmap = mvi->rsvd_tags; 4062306a36Sopenharmony_ci set_bit(tag, bitmap); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci unsigned int index, tag; 4662306a36Sopenharmony_ci void *bitmap = mvi->rsvd_tags; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci index = find_first_zero_bit(bitmap, MVS_RSVD_SLOTS); 4962306a36Sopenharmony_ci tag = index; 5062306a36Sopenharmony_ci if (tag >= MVS_RSVD_SLOTS) 5162306a36Sopenharmony_ci return -SAS_QUEUE_FULL; 5262306a36Sopenharmony_ci mvs_tag_set(mvi, tag); 5362306a36Sopenharmony_ci *tag_out = tag; 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci unsigned long i = 0, j = 0, hi = 0; 6062306a36Sopenharmony_ci struct sas_ha_struct *sha = dev->port->ha; 6162306a36Sopenharmony_ci struct mvs_info *mvi = NULL; 6262306a36Sopenharmony_ci struct asd_sas_phy *phy; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci while (sha->sas_port[i]) { 6562306a36Sopenharmony_ci if (sha->sas_port[i] == dev->port) { 6662306a36Sopenharmony_ci spin_lock(&sha->sas_port[i]->phy_list_lock); 6762306a36Sopenharmony_ci phy = container_of(sha->sas_port[i]->phy_list.next, 6862306a36Sopenharmony_ci struct asd_sas_phy, port_phy_el); 6962306a36Sopenharmony_ci spin_unlock(&sha->sas_port[i]->phy_list_lock); 7062306a36Sopenharmony_ci j = 0; 7162306a36Sopenharmony_ci while (sha->sas_phy[j]) { 7262306a36Sopenharmony_ci if (sha->sas_phy[j] == phy) 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci j++; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci i++; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; 8162306a36Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return mvi; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long i = 0, j = 0, n = 0, num = 0; 9062306a36Sopenharmony_ci struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 9162306a36Sopenharmony_ci struct mvs_info *mvi = mvi_dev->mvi_info; 9262306a36Sopenharmony_ci struct sas_ha_struct *sha = dev->port->ha; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci while (sha->sas_port[i]) { 9562306a36Sopenharmony_ci if (sha->sas_port[i] == dev->port) { 9662306a36Sopenharmony_ci struct asd_sas_phy *phy; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock(&sha->sas_port[i]->phy_list_lock); 9962306a36Sopenharmony_ci list_for_each_entry(phy, 10062306a36Sopenharmony_ci &sha->sas_port[i]->phy_list, port_phy_el) { 10162306a36Sopenharmony_ci j = 0; 10262306a36Sopenharmony_ci while (sha->sas_phy[j]) { 10362306a36Sopenharmony_ci if (sha->sas_phy[j] == phy) 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci j++; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci phyno[n] = (j >= mvi->chip->n_phy) ? 10862306a36Sopenharmony_ci (j - mvi->chip->n_phy) : j; 10962306a36Sopenharmony_ci num++; 11062306a36Sopenharmony_ci n++; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci spin_unlock(&sha->sas_port[i]->phy_list_lock); 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci i++; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci return num; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistruct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, 12162306a36Sopenharmony_ci u8 reg_set) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci u32 dev_no; 12462306a36Sopenharmony_ci for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) { 12562306a36Sopenharmony_ci if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED) 12662306a36Sopenharmony_ci continue; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (mvi->devices[dev_no].taskfileset == reg_set) 12962306a36Sopenharmony_ci return &mvi->devices[dev_no]; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci return NULL; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline void mvs_free_reg_set(struct mvs_info *mvi, 13562306a36Sopenharmony_ci struct mvs_device *dev) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci if (!dev) { 13862306a36Sopenharmony_ci mv_printk("device has been free.\n"); 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci if (dev->taskfileset == MVS_ID_NOT_MAPPED) 14262306a36Sopenharmony_ci return; 14362306a36Sopenharmony_ci MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic inline u8 mvs_assign_reg_set(struct mvs_info *mvi, 14762306a36Sopenharmony_ci struct mvs_device *dev) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci if (dev->taskfileset != MVS_ID_NOT_MAPPED) 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_civoid mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci u32 no; 15762306a36Sopenharmony_ci for_each_phy(phy_mask, phy_mask, no) { 15862306a36Sopenharmony_ci if (!(phy_mask & 1)) 15962306a36Sopenharmony_ci continue; 16062306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, no, hard); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, 16562306a36Sopenharmony_ci void *funcdata) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int rc = 0, phy_id = sas_phy->id; 16862306a36Sopenharmony_ci u32 tmp, i = 0, hi; 16962306a36Sopenharmony_ci struct sas_ha_struct *sha = sas_phy->ha; 17062306a36Sopenharmony_ci struct mvs_info *mvi = NULL; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci while (sha->sas_phy[i]) { 17362306a36Sopenharmony_ci if (sha->sas_phy[i] == sas_phy) 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci i++; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; 17862306a36Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci switch (func) { 18162306a36Sopenharmony_ci case PHY_FUNC_SET_LINK_RATE: 18262306a36Sopenharmony_ci MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata); 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci case PHY_FUNC_HARD_RESET: 18662306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); 18762306a36Sopenharmony_ci if (tmp & PHY_RST_HARD) 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET); 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci case PHY_FUNC_LINK_RESET: 19362306a36Sopenharmony_ci MVS_CHIP_DISP->phy_enable(mvi, phy_id); 19462306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci case PHY_FUNC_DISABLE: 19862306a36Sopenharmony_ci MVS_CHIP_DISP->phy_disable(mvi, phy_id); 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci case PHY_FUNC_RELEASE_SPINUP_HOLD: 20162306a36Sopenharmony_ci default: 20262306a36Sopenharmony_ci rc = -ENOSYS; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci msleep(200); 20562306a36Sopenharmony_ci return rc; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_civoid mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo, 20962306a36Sopenharmony_ci u32 off_hi, u64 sas_addr) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci u32 lo = (u32)sas_addr; 21262306a36Sopenharmony_ci u32 hi = (u32)(sas_addr>>32); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo); 21562306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo); 21662306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi); 21762306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i, gfp_t gfp_flags) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 22362306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!phy->phy_attached) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK) 22962306a36Sopenharmony_ci && phy->phy_type & PORT_TYPE_SAS) { 23062306a36Sopenharmony_ci return; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci sas_notify_phy_event(sas_phy, PHYE_OOB_DONE, gfp_flags); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (sas_phy->phy) { 23662306a36Sopenharmony_ci struct sas_phy *sphy = sas_phy->phy; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci sphy->negotiated_linkrate = sas_phy->linkrate; 23962306a36Sopenharmony_ci sphy->minimum_linkrate = phy->minimum_linkrate; 24062306a36Sopenharmony_ci sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 24162306a36Sopenharmony_ci sphy->maximum_linkrate = phy->maximum_linkrate; 24262306a36Sopenharmony_ci sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate(); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 24662306a36Sopenharmony_ci struct sas_identify_frame *id; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci id = (struct sas_identify_frame *)phy->frame_rcvd; 24962306a36Sopenharmony_ci id->dev_type = phy->identify.device_type; 25062306a36Sopenharmony_ci id->initiator_bits = SAS_PROTOCOL_ALL; 25162306a36Sopenharmony_ci id->target_bits = phy->identify.target_port_protocols; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* direct attached SAS device */ 25462306a36Sopenharmony_ci if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { 25562306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 25662306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x00); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } else if (phy->phy_type & PORT_TYPE_SATA) { 25962306a36Sopenharmony_ci /*Nothing*/ 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci sas_phy->frame_rcvd_size = phy->frame_rcvd_size; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED, gfp_flags); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_civoid mvs_scan_start(struct Scsi_Host *shost) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int i, j; 27162306a36Sopenharmony_ci unsigned short core_nr; 27262306a36Sopenharmony_ci struct mvs_info *mvi; 27362306a36Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 27462306a36Sopenharmony_ci struct mvs_prv_info *mvs_prv = sha->lldd_ha; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (j = 0; j < core_nr; j++) { 27962306a36Sopenharmony_ci mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; 28062306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; ++i) 28162306a36Sopenharmony_ci mvs_bytes_dmaed(mvi, i, GFP_KERNEL); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci mvs_prv->scan_finished = 1; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ciint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 28962306a36Sopenharmony_ci struct mvs_prv_info *mvs_prv = sha->lldd_ha; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (mvs_prv->scan_finished == 0) 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci sas_drain_work(sha); 29562306a36Sopenharmony_ci return 1; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int mvs_task_prep_smp(struct mvs_info *mvi, 29962306a36Sopenharmony_ci struct mvs_task_exec_info *tei) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int elem, rc, i; 30262306a36Sopenharmony_ci struct sas_ha_struct *sha = mvi->sas; 30362306a36Sopenharmony_ci struct sas_task *task = tei->task; 30462306a36Sopenharmony_ci struct mvs_cmd_hdr *hdr = tei->hdr; 30562306a36Sopenharmony_ci struct domain_device *dev = task->dev; 30662306a36Sopenharmony_ci struct asd_sas_port *sas_port = dev->port; 30762306a36Sopenharmony_ci struct sas_phy *sphy = dev->phy; 30862306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = sha->sas_phy[sphy->number]; 30962306a36Sopenharmony_ci struct scatterlist *sg_req, *sg_resp; 31062306a36Sopenharmony_ci u32 req_len, resp_len, tag = tei->tag; 31162306a36Sopenharmony_ci void *buf_tmp; 31262306a36Sopenharmony_ci u8 *buf_oaf; 31362306a36Sopenharmony_ci dma_addr_t buf_tmp_dma; 31462306a36Sopenharmony_ci void *buf_prd; 31562306a36Sopenharmony_ci struct mvs_slot_info *slot = &mvi->slot_info[tag]; 31662306a36Sopenharmony_ci u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * DMA-map SMP request, response buffers 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_ci sg_req = &task->smp_task.smp_req; 32262306a36Sopenharmony_ci elem = dma_map_sg(mvi->dev, sg_req, 1, DMA_TO_DEVICE); 32362306a36Sopenharmony_ci if (!elem) 32462306a36Sopenharmony_ci return -ENOMEM; 32562306a36Sopenharmony_ci req_len = sg_dma_len(sg_req); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci sg_resp = &task->smp_task.smp_resp; 32862306a36Sopenharmony_ci elem = dma_map_sg(mvi->dev, sg_resp, 1, DMA_FROM_DEVICE); 32962306a36Sopenharmony_ci if (!elem) { 33062306a36Sopenharmony_ci rc = -ENOMEM; 33162306a36Sopenharmony_ci goto err_out; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci resp_len = SB_RFB_MAX; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* must be in dwords */ 33662306a36Sopenharmony_ci if ((req_len & 0x3) || (resp_len & 0x3)) { 33762306a36Sopenharmony_ci rc = -EINVAL; 33862306a36Sopenharmony_ci goto err_out_2; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */ 34662306a36Sopenharmony_ci buf_tmp = slot->buf; 34762306a36Sopenharmony_ci buf_tmp_dma = slot->buf_dma; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 35262306a36Sopenharmony_ci buf_oaf = buf_tmp; 35362306a36Sopenharmony_ci hdr->open_frame = cpu_to_le64(buf_tmp_dma); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci buf_tmp += MVS_OAF_SZ; 35662306a36Sopenharmony_ci buf_tmp_dma += MVS_OAF_SZ; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* region 3: PRD table *********************************** */ 35962306a36Sopenharmony_ci buf_prd = buf_tmp; 36062306a36Sopenharmony_ci if (tei->n_elem) 36162306a36Sopenharmony_ci hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 36262306a36Sopenharmony_ci else 36362306a36Sopenharmony_ci hdr->prd_tbl = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci i = MVS_CHIP_DISP->prd_size() * tei->n_elem; 36662306a36Sopenharmony_ci buf_tmp += i; 36762306a36Sopenharmony_ci buf_tmp_dma += i; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 37062306a36Sopenharmony_ci slot->response = buf_tmp; 37162306a36Sopenharmony_ci hdr->status_buf = cpu_to_le64(buf_tmp_dma); 37262306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 37362306a36Sopenharmony_ci hdr->reserved[0] = 0; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Fill in TX ring and command slot header 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci slot->tx = mvi->tx_prod; 37962306a36Sopenharmony_ci mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | 38062306a36Sopenharmony_ci TXQ_MODE_I | tag | 38162306a36Sopenharmony_ci (MVS_PHY_ID << TXQ_PHY_SHIFT)); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci hdr->flags |= flags; 38462306a36Sopenharmony_ci hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); 38562306a36Sopenharmony_ci hdr->tags = cpu_to_le32(tag); 38662306a36Sopenharmony_ci hdr->data_len = 0; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* generate open address frame hdr (first 12 bytes) */ 38962306a36Sopenharmony_ci /* initiator, SMP, ftype 1h */ 39062306a36Sopenharmony_ci buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01; 39162306a36Sopenharmony_ci buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 39262306a36Sopenharmony_ci *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ 39362306a36Sopenharmony_ci memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 39662306a36Sopenharmony_ci MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cierr_out_2: 40162306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1, 40262306a36Sopenharmony_ci DMA_FROM_DEVICE); 40362306a36Sopenharmony_cierr_out: 40462306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1, 40562306a36Sopenharmony_ci DMA_TO_DEVICE); 40662306a36Sopenharmony_ci return rc; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct ata_queued_cmd *qc = task->uldd_task; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (qc) { 41462306a36Sopenharmony_ci if (qc->tf.command == ATA_CMD_FPDMA_WRITE || 41562306a36Sopenharmony_ci qc->tf.command == ATA_CMD_FPDMA_READ || 41662306a36Sopenharmony_ci qc->tf.command == ATA_CMD_FPDMA_RECV || 41762306a36Sopenharmony_ci qc->tf.command == ATA_CMD_FPDMA_SEND || 41862306a36Sopenharmony_ci qc->tf.command == ATA_CMD_NCQ_NON_DATA) { 41962306a36Sopenharmony_ci *tag = qc->tag; 42062306a36Sopenharmony_ci return 1; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic int mvs_task_prep_ata(struct mvs_info *mvi, 42862306a36Sopenharmony_ci struct mvs_task_exec_info *tei) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct sas_task *task = tei->task; 43162306a36Sopenharmony_ci struct domain_device *dev = task->dev; 43262306a36Sopenharmony_ci struct mvs_device *mvi_dev = dev->lldd_dev; 43362306a36Sopenharmony_ci struct mvs_cmd_hdr *hdr = tei->hdr; 43462306a36Sopenharmony_ci struct asd_sas_port *sas_port = dev->port; 43562306a36Sopenharmony_ci struct mvs_slot_info *slot; 43662306a36Sopenharmony_ci void *buf_prd; 43762306a36Sopenharmony_ci u32 tag = tei->tag, hdr_tag; 43862306a36Sopenharmony_ci u32 flags, del_q; 43962306a36Sopenharmony_ci void *buf_tmp; 44062306a36Sopenharmony_ci u8 *buf_cmd, *buf_oaf; 44162306a36Sopenharmony_ci dma_addr_t buf_tmp_dma; 44262306a36Sopenharmony_ci u32 i, req_len, resp_len; 44362306a36Sopenharmony_ci const u32 max_resp_len = SB_RFB_MAX; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) { 44662306a36Sopenharmony_ci mv_dprintk("Have not enough regiset for dev %d.\n", 44762306a36Sopenharmony_ci mvi_dev->device_id); 44862306a36Sopenharmony_ci return -EBUSY; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci slot = &mvi->slot_info[tag]; 45162306a36Sopenharmony_ci slot->tx = mvi->tx_prod; 45262306a36Sopenharmony_ci del_q = TXQ_MODE_I | tag | 45362306a36Sopenharmony_ci (TXQ_CMD_STP << TXQ_CMD_SHIFT) | 45462306a36Sopenharmony_ci ((sas_port->phy_mask & TXQ_PHY_MASK) << TXQ_PHY_SHIFT) | 45562306a36Sopenharmony_ci (mvi_dev->taskfileset << TXQ_SRS_SHIFT); 45662306a36Sopenharmony_ci mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (task->data_dir == DMA_FROM_DEVICE) 45962306a36Sopenharmony_ci flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT); 46062306a36Sopenharmony_ci else 46162306a36Sopenharmony_ci flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (task->ata_task.use_ncq) 46462306a36Sopenharmony_ci flags |= MCH_FPDMA; 46562306a36Sopenharmony_ci if (dev->sata_dev.class == ATA_DEV_ATAPI) { 46662306a36Sopenharmony_ci if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) 46762306a36Sopenharmony_ci flags |= MCH_ATAPI; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci hdr->flags = cpu_to_le32(flags); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag)) 47362306a36Sopenharmony_ci task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); 47462306a36Sopenharmony_ci else 47562306a36Sopenharmony_ci hdr_tag = tag; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci hdr->tags = cpu_to_le32(hdr_tag); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci hdr->data_len = cpu_to_le32(task->total_xfer_len); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ 48662306a36Sopenharmony_ci buf_cmd = buf_tmp = slot->buf; 48762306a36Sopenharmony_ci buf_tmp_dma = slot->buf_dma; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci buf_tmp += MVS_ATA_CMD_SZ; 49262306a36Sopenharmony_ci buf_tmp_dma += MVS_ATA_CMD_SZ; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 49562306a36Sopenharmony_ci /* used for STP. unused for SATA? */ 49662306a36Sopenharmony_ci buf_oaf = buf_tmp; 49762306a36Sopenharmony_ci hdr->open_frame = cpu_to_le64(buf_tmp_dma); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci buf_tmp += MVS_OAF_SZ; 50062306a36Sopenharmony_ci buf_tmp_dma += MVS_OAF_SZ; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* region 3: PRD table ********************************************* */ 50362306a36Sopenharmony_ci buf_prd = buf_tmp; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (tei->n_elem) 50662306a36Sopenharmony_ci hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 50762306a36Sopenharmony_ci else 50862306a36Sopenharmony_ci hdr->prd_tbl = 0; 50962306a36Sopenharmony_ci i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count(); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci buf_tmp += i; 51262306a36Sopenharmony_ci buf_tmp_dma += i; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 51562306a36Sopenharmony_ci slot->response = buf_tmp; 51662306a36Sopenharmony_ci hdr->status_buf = cpu_to_le64(buf_tmp_dma); 51762306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 51862306a36Sopenharmony_ci hdr->reserved[0] = 0; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci req_len = sizeof(struct host_to_dev_fis); 52162306a36Sopenharmony_ci resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - 52262306a36Sopenharmony_ci sizeof(struct mvs_err_info) - i; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* request, response lengths */ 52562306a36Sopenharmony_ci resp_len = min(resp_len, max_resp_len); 52662306a36Sopenharmony_ci hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (likely(!task->ata_task.device_control_reg_update)) 52962306a36Sopenharmony_ci task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ 53062306a36Sopenharmony_ci /* fill in command FIS and ATAPI CDB */ 53162306a36Sopenharmony_ci memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); 53262306a36Sopenharmony_ci if (dev->sata_dev.class == ATA_DEV_ATAPI) 53362306a36Sopenharmony_ci memcpy(buf_cmd + STP_ATAPI_CMD, 53462306a36Sopenharmony_ci task->ata_task.atapi_packet, 16); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* generate open address frame hdr (first 12 bytes) */ 53762306a36Sopenharmony_ci /* initiator, STP, ftype 1h */ 53862306a36Sopenharmony_ci buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1; 53962306a36Sopenharmony_ci buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 54062306a36Sopenharmony_ci *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); 54162306a36Sopenharmony_ci memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 54462306a36Sopenharmony_ci MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (task->data_dir == DMA_FROM_DEVICE) 54762306a36Sopenharmony_ci MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask, 54862306a36Sopenharmony_ci TRASH_BUCKET_SIZE, tei->n_elem, buf_prd); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int mvs_task_prep_ssp(struct mvs_info *mvi, 55462306a36Sopenharmony_ci struct mvs_task_exec_info *tei, int is_tmf, 55562306a36Sopenharmony_ci struct sas_tmf_task *tmf) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct sas_task *task = tei->task; 55862306a36Sopenharmony_ci struct mvs_cmd_hdr *hdr = tei->hdr; 55962306a36Sopenharmony_ci struct mvs_port *port = tei->port; 56062306a36Sopenharmony_ci struct domain_device *dev = task->dev; 56162306a36Sopenharmony_ci struct mvs_device *mvi_dev = dev->lldd_dev; 56262306a36Sopenharmony_ci struct asd_sas_port *sas_port = dev->port; 56362306a36Sopenharmony_ci struct mvs_slot_info *slot; 56462306a36Sopenharmony_ci void *buf_prd; 56562306a36Sopenharmony_ci struct ssp_frame_hdr *ssp_hdr; 56662306a36Sopenharmony_ci void *buf_tmp; 56762306a36Sopenharmony_ci u8 *buf_cmd, *buf_oaf; 56862306a36Sopenharmony_ci dma_addr_t buf_tmp_dma; 56962306a36Sopenharmony_ci u32 flags; 57062306a36Sopenharmony_ci u32 resp_len, req_len, i, tag = tei->tag; 57162306a36Sopenharmony_ci const u32 max_resp_len = SB_RFB_MAX; 57262306a36Sopenharmony_ci u32 phy_mask; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci slot = &mvi->slot_info[tag]; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap : 57762306a36Sopenharmony_ci sas_port->phy_mask) & TXQ_PHY_MASK; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci slot->tx = mvi->tx_prod; 58062306a36Sopenharmony_ci mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | 58162306a36Sopenharmony_ci (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | 58262306a36Sopenharmony_ci (phy_mask << TXQ_PHY_SHIFT)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci flags = MCH_RETRY; 58562306a36Sopenharmony_ci if (is_tmf) 58662306a36Sopenharmony_ci flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT); 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT)); 59162306a36Sopenharmony_ci hdr->tags = cpu_to_le32(tag); 59262306a36Sopenharmony_ci hdr->data_len = cpu_to_le32(task->total_xfer_len); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ 59962306a36Sopenharmony_ci buf_cmd = buf_tmp = slot->buf; 60062306a36Sopenharmony_ci buf_tmp_dma = slot->buf_dma; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci buf_tmp += MVS_SSP_CMD_SZ; 60562306a36Sopenharmony_ci buf_tmp_dma += MVS_SSP_CMD_SZ; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 60862306a36Sopenharmony_ci buf_oaf = buf_tmp; 60962306a36Sopenharmony_ci hdr->open_frame = cpu_to_le64(buf_tmp_dma); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci buf_tmp += MVS_OAF_SZ; 61262306a36Sopenharmony_ci buf_tmp_dma += MVS_OAF_SZ; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* region 3: PRD table ********************************************* */ 61562306a36Sopenharmony_ci buf_prd = buf_tmp; 61662306a36Sopenharmony_ci if (tei->n_elem) 61762306a36Sopenharmony_ci hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 61862306a36Sopenharmony_ci else 61962306a36Sopenharmony_ci hdr->prd_tbl = 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci i = MVS_CHIP_DISP->prd_size() * tei->n_elem; 62262306a36Sopenharmony_ci buf_tmp += i; 62362306a36Sopenharmony_ci buf_tmp_dma += i; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 62662306a36Sopenharmony_ci slot->response = buf_tmp; 62762306a36Sopenharmony_ci hdr->status_buf = cpu_to_le64(buf_tmp_dma); 62862306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) 62962306a36Sopenharmony_ci hdr->reserved[0] = 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - 63262306a36Sopenharmony_ci sizeof(struct mvs_err_info) - i; 63362306a36Sopenharmony_ci resp_len = min(resp_len, max_resp_len); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci req_len = sizeof(struct ssp_frame_hdr) + 28; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* request, response lengths */ 63862306a36Sopenharmony_ci hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* generate open address frame hdr (first 12 bytes) */ 64162306a36Sopenharmony_ci /* initiator, SSP, ftype 1h */ 64262306a36Sopenharmony_ci buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1; 64362306a36Sopenharmony_ci buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 64462306a36Sopenharmony_ci *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); 64562306a36Sopenharmony_ci memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* fill in SSP frame header (Command Table.SSP frame header) */ 64862306a36Sopenharmony_ci ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (is_tmf) 65162306a36Sopenharmony_ci ssp_hdr->frame_type = SSP_TASK; 65262306a36Sopenharmony_ci else 65362306a36Sopenharmony_ci ssp_hdr->frame_type = SSP_COMMAND; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr, 65662306a36Sopenharmony_ci HASHED_SAS_ADDR_SIZE); 65762306a36Sopenharmony_ci memcpy(ssp_hdr->hashed_src_addr, 65862306a36Sopenharmony_ci dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); 65962306a36Sopenharmony_ci ssp_hdr->tag = cpu_to_be16(tag); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* fill in IU for TASK and Command Frame */ 66262306a36Sopenharmony_ci buf_cmd += sizeof(*ssp_hdr); 66362306a36Sopenharmony_ci memcpy(buf_cmd, &task->ssp_task.LUN, 8); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (ssp_hdr->frame_type != SSP_TASK) { 66662306a36Sopenharmony_ci buf_cmd[9] = task->ssp_task.task_attr; 66762306a36Sopenharmony_ci memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd, 66862306a36Sopenharmony_ci task->ssp_task.cmd->cmd_len); 66962306a36Sopenharmony_ci } else{ 67062306a36Sopenharmony_ci buf_cmd[10] = tmf->tmf; 67162306a36Sopenharmony_ci switch (tmf->tmf) { 67262306a36Sopenharmony_ci case TMF_ABORT_TASK: 67362306a36Sopenharmony_ci case TMF_QUERY_TASK: 67462306a36Sopenharmony_ci buf_cmd[12] = 67562306a36Sopenharmony_ci (tmf->tag_of_task_to_be_managed >> 8) & 0xff; 67662306a36Sopenharmony_ci buf_cmd[13] = 67762306a36Sopenharmony_ci tmf->tag_of_task_to_be_managed & 0xff; 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci default: 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 68462306a36Sopenharmony_ci MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == SAS_PHY_UNUSED))) 68962306a36Sopenharmony_cistatic int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, 69062306a36Sopenharmony_ci struct sas_tmf_task *tmf, int *pass) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct domain_device *dev = task->dev; 69362306a36Sopenharmony_ci struct mvs_device *mvi_dev = dev->lldd_dev; 69462306a36Sopenharmony_ci struct mvs_task_exec_info tei; 69562306a36Sopenharmony_ci struct mvs_slot_info *slot; 69662306a36Sopenharmony_ci u32 tag = 0xdeadbeef, n_elem = 0; 69762306a36Sopenharmony_ci struct request *rq; 69862306a36Sopenharmony_ci int rc = 0; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (!dev->port) { 70162306a36Sopenharmony_ci struct task_status_struct *tsm = &task->task_status; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci tsm->resp = SAS_TASK_UNDELIVERED; 70462306a36Sopenharmony_ci tsm->stat = SAS_PHY_DOWN; 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * libsas will use dev->port, should 70762306a36Sopenharmony_ci * not call task_done for sata 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci if (dev->dev_type != SAS_SATA_DEV) 71062306a36Sopenharmony_ci task->task_done(task); 71162306a36Sopenharmony_ci return rc; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (DEV_IS_GONE(mvi_dev)) { 71562306a36Sopenharmony_ci if (mvi_dev) 71662306a36Sopenharmony_ci mv_dprintk("device %d not ready.\n", 71762306a36Sopenharmony_ci mvi_dev->device_id); 71862306a36Sopenharmony_ci else 71962306a36Sopenharmony_ci mv_dprintk("device %016llx not ready.\n", 72062306a36Sopenharmony_ci SAS_ADDR(dev->sas_addr)); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci rc = SAS_PHY_DOWN; 72362306a36Sopenharmony_ci return rc; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci tei.port = dev->port->lldd_port; 72662306a36Sopenharmony_ci if (tei.port && !tei.port->port_attached && !tmf) { 72762306a36Sopenharmony_ci if (sas_protocol_ata(task->task_proto)) { 72862306a36Sopenharmony_ci struct task_status_struct *ts = &task->task_status; 72962306a36Sopenharmony_ci mv_dprintk("SATA/STP port %d does not attach" 73062306a36Sopenharmony_ci "device.\n", dev->port->id); 73162306a36Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 73262306a36Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci task->task_done(task); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci } else { 73762306a36Sopenharmony_ci struct task_status_struct *ts = &task->task_status; 73862306a36Sopenharmony_ci mv_dprintk("SAS port %d does not attach" 73962306a36Sopenharmony_ci "device.\n", dev->port->id); 74062306a36Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 74162306a36Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 74262306a36Sopenharmony_ci task->task_done(task); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci return rc; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) { 74862306a36Sopenharmony_ci if (task->num_scatter) { 74962306a36Sopenharmony_ci n_elem = dma_map_sg(mvi->dev, 75062306a36Sopenharmony_ci task->scatter, 75162306a36Sopenharmony_ci task->num_scatter, 75262306a36Sopenharmony_ci task->data_dir); 75362306a36Sopenharmony_ci if (!n_elem) { 75462306a36Sopenharmony_ci rc = -ENOMEM; 75562306a36Sopenharmony_ci goto prep_out; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci n_elem = task->num_scatter; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci rq = sas_task_find_rq(task); 76362306a36Sopenharmony_ci if (rq) { 76462306a36Sopenharmony_ci tag = rq->tag + MVS_RSVD_SLOTS; 76562306a36Sopenharmony_ci } else { 76662306a36Sopenharmony_ci rc = mvs_tag_alloc(mvi, &tag); 76762306a36Sopenharmony_ci if (rc) 76862306a36Sopenharmony_ci goto err_out; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci slot = &mvi->slot_info[tag]; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci task->lldd_task = NULL; 77462306a36Sopenharmony_ci slot->n_elem = n_elem; 77562306a36Sopenharmony_ci slot->slot_tag = tag; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci slot->buf = dma_pool_zalloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma); 77862306a36Sopenharmony_ci if (!slot->buf) { 77962306a36Sopenharmony_ci rc = -ENOMEM; 78062306a36Sopenharmony_ci goto err_out_tag; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci tei.task = task; 78462306a36Sopenharmony_ci tei.hdr = &mvi->slot[tag]; 78562306a36Sopenharmony_ci tei.tag = tag; 78662306a36Sopenharmony_ci tei.n_elem = n_elem; 78762306a36Sopenharmony_ci switch (task->task_proto) { 78862306a36Sopenharmony_ci case SAS_PROTOCOL_SMP: 78962306a36Sopenharmony_ci rc = mvs_task_prep_smp(mvi, &tei); 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case SAS_PROTOCOL_SSP: 79262306a36Sopenharmony_ci rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci case SAS_PROTOCOL_SATA: 79562306a36Sopenharmony_ci case SAS_PROTOCOL_STP: 79662306a36Sopenharmony_ci case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 79762306a36Sopenharmony_ci rc = mvs_task_prep_ata(mvi, &tei); 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci default: 80062306a36Sopenharmony_ci dev_printk(KERN_ERR, mvi->dev, 80162306a36Sopenharmony_ci "unknown sas_task proto: 0x%x\n", 80262306a36Sopenharmony_ci task->task_proto); 80362306a36Sopenharmony_ci rc = -EINVAL; 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (rc) { 80862306a36Sopenharmony_ci mv_dprintk("rc is %x\n", rc); 80962306a36Sopenharmony_ci goto err_out_slot_buf; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci slot->task = task; 81262306a36Sopenharmony_ci slot->port = tei.port; 81362306a36Sopenharmony_ci task->lldd_task = slot; 81462306a36Sopenharmony_ci list_add_tail(&slot->entry, &tei.port->list); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci mvi_dev->running_req++; 81762306a36Sopenharmony_ci ++(*pass); 81862306a36Sopenharmony_ci mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return rc; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cierr_out_slot_buf: 82362306a36Sopenharmony_ci dma_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); 82462306a36Sopenharmony_cierr_out_tag: 82562306a36Sopenharmony_ci mvs_tag_free(mvi, tag); 82662306a36Sopenharmony_cierr_out: 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); 82962306a36Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) 83062306a36Sopenharmony_ci if (n_elem) 83162306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, task->scatter, n_elem, 83262306a36Sopenharmony_ci task->data_dir); 83362306a36Sopenharmony_ciprep_out: 83462306a36Sopenharmony_ci return rc; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ciint mvs_queue_command(struct sas_task *task, gfp_t gfp_flags) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct mvs_info *mvi = NULL; 84062306a36Sopenharmony_ci u32 rc = 0; 84162306a36Sopenharmony_ci u32 pass = 0; 84262306a36Sopenharmony_ci unsigned long flags = 0; 84362306a36Sopenharmony_ci struct sas_tmf_task *tmf = task->tmf; 84462306a36Sopenharmony_ci int is_tmf = !!task->tmf; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 84962306a36Sopenharmony_ci rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); 85062306a36Sopenharmony_ci if (rc) 85162306a36Sopenharmony_ci dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (likely(pass)) 85462306a36Sopenharmony_ci MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & 85562306a36Sopenharmony_ci (MVS_CHIP_SLOT_SZ - 1)); 85662306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci return rc; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 86462306a36Sopenharmony_ci mvs_tag_free(mvi, slot_idx); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, 86862306a36Sopenharmony_ci struct mvs_slot_info *slot, u32 slot_idx) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci if (!slot) 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci if (!slot->task) 87362306a36Sopenharmony_ci return; 87462306a36Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) 87562306a36Sopenharmony_ci if (slot->n_elem) 87662306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, task->scatter, 87762306a36Sopenharmony_ci slot->n_elem, task->data_dir); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci switch (task->task_proto) { 88062306a36Sopenharmony_ci case SAS_PROTOCOL_SMP: 88162306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1, 88262306a36Sopenharmony_ci DMA_FROM_DEVICE); 88362306a36Sopenharmony_ci dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1, 88462306a36Sopenharmony_ci DMA_TO_DEVICE); 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci case SAS_PROTOCOL_SATA: 88862306a36Sopenharmony_ci case SAS_PROTOCOL_STP: 88962306a36Sopenharmony_ci case SAS_PROTOCOL_SSP: 89062306a36Sopenharmony_ci default: 89162306a36Sopenharmony_ci /* do nothing */ 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (slot->buf) { 89662306a36Sopenharmony_ci dma_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); 89762306a36Sopenharmony_ci slot->buf = NULL; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci list_del_init(&slot->entry); 90062306a36Sopenharmony_ci task->lldd_task = NULL; 90162306a36Sopenharmony_ci slot->task = NULL; 90262306a36Sopenharmony_ci slot->port = NULL; 90362306a36Sopenharmony_ci slot->slot_tag = 0xFFFFFFFF; 90462306a36Sopenharmony_ci mvs_slot_free(mvi, slot_idx); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic void mvs_update_wideport(struct mvs_info *mvi, int phy_no) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[phy_no]; 91062306a36Sopenharmony_ci struct mvs_port *port = phy->port; 91162306a36Sopenharmony_ci int j, no; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci for_each_phy(port->wide_port_phymap, j, no) { 91462306a36Sopenharmony_ci if (j & 1) { 91562306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, 91662306a36Sopenharmony_ci PHYR_WIDE_PORT); 91762306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, no, 91862306a36Sopenharmony_ci port->wide_port_phymap); 91962306a36Sopenharmony_ci } else { 92062306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, 92162306a36Sopenharmony_ci PHYR_WIDE_PORT); 92262306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, no, 92362306a36Sopenharmony_ci 0); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci u32 tmp; 93162306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 93262306a36Sopenharmony_ci struct mvs_port *port = phy->port; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i); 93562306a36Sopenharmony_ci if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { 93662306a36Sopenharmony_ci if (!port) 93762306a36Sopenharmony_ci phy->phy_attached = 1; 93862306a36Sopenharmony_ci return tmp; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (port) { 94262306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 94362306a36Sopenharmony_ci port->wide_port_phymap &= ~(1U << i); 94462306a36Sopenharmony_ci if (!port->wide_port_phymap) 94562306a36Sopenharmony_ci port->port_attached = 0; 94662306a36Sopenharmony_ci mvs_update_wideport(mvi, i); 94762306a36Sopenharmony_ci } else if (phy->phy_type & PORT_TYPE_SATA) 94862306a36Sopenharmony_ci port->port_attached = 0; 94962306a36Sopenharmony_ci phy->port = NULL; 95062306a36Sopenharmony_ci phy->phy_attached = 0; 95162306a36Sopenharmony_ci phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci u32 *s = (u32 *) buf; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (!s) 96162306a36Sopenharmony_ci return NULL; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); 96462306a36Sopenharmony_ci s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); 96762306a36Sopenharmony_ci s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); 97062306a36Sopenharmony_ci s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); 97362306a36Sopenharmony_ci s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01)) 97662306a36Sopenharmony_ci s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return s; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic u32 mvs_is_sig_fis_received(u32 irq_status) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci return irq_status & PHYEV_SIG_FIS; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic void mvs_sig_remove_timer(struct mvs_phy *phy) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci if (phy->timer.function) 98962306a36Sopenharmony_ci del_timer(&phy->timer); 99062306a36Sopenharmony_ci phy->timer.function = NULL; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_civoid mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 99662306a36Sopenharmony_ci struct sas_identify_frame *id; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci id = (struct sas_identify_frame *)phy->frame_rcvd; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (get_st) { 100162306a36Sopenharmony_ci phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i); 100262306a36Sopenharmony_ci phy->phy_status = mvs_is_phy_ready(mvi, i); 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (phy->phy_status) { 100662306a36Sopenharmony_ci int oob_done = 0; 100762306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci oob_done = MVS_CHIP_DISP->oob_done(mvi, i); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci MVS_CHIP_DISP->fix_phy_info(mvi, i, id); 101262306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SATA) { 101362306a36Sopenharmony_ci phy->identify.target_port_protocols = SAS_PROTOCOL_STP; 101462306a36Sopenharmony_ci if (mvs_is_sig_fis_received(phy->irq_status)) { 101562306a36Sopenharmony_ci mvs_sig_remove_timer(phy); 101662306a36Sopenharmony_ci phy->phy_attached = 1; 101762306a36Sopenharmony_ci phy->att_dev_sas_addr = 101862306a36Sopenharmony_ci i + mvi->id * mvi->chip->n_phy; 101962306a36Sopenharmony_ci if (oob_done) 102062306a36Sopenharmony_ci sas_phy->oob_mode = SATA_OOB_MODE; 102162306a36Sopenharmony_ci phy->frame_rcvd_size = 102262306a36Sopenharmony_ci sizeof(struct dev_to_host_fis); 102362306a36Sopenharmony_ci mvs_get_d2h_reg(mvi, i, id); 102462306a36Sopenharmony_ci } else { 102562306a36Sopenharmony_ci u32 tmp; 102662306a36Sopenharmony_ci dev_printk(KERN_DEBUG, mvi->dev, 102762306a36Sopenharmony_ci "Phy%d : No sig fis\n", i); 102862306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i); 102962306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_irq_mask(mvi, i, 103062306a36Sopenharmony_ci tmp | PHYEV_SIG_FIS); 103162306a36Sopenharmony_ci phy->phy_attached = 0; 103262306a36Sopenharmony_ci phy->phy_type &= ~PORT_TYPE_SATA; 103362306a36Sopenharmony_ci goto out_done; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci } else if (phy->phy_type & PORT_TYPE_SAS 103662306a36Sopenharmony_ci || phy->att_dev_info & PORT_SSP_INIT_MASK) { 103762306a36Sopenharmony_ci phy->phy_attached = 1; 103862306a36Sopenharmony_ci phy->identify.device_type = 103962306a36Sopenharmony_ci phy->att_dev_info & PORT_DEV_TYPE_MASK; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (phy->identify.device_type == SAS_END_DEVICE) 104262306a36Sopenharmony_ci phy->identify.target_port_protocols = 104362306a36Sopenharmony_ci SAS_PROTOCOL_SSP; 104462306a36Sopenharmony_ci else if (phy->identify.device_type != SAS_PHY_UNUSED) 104562306a36Sopenharmony_ci phy->identify.target_port_protocols = 104662306a36Sopenharmony_ci SAS_PROTOCOL_SMP; 104762306a36Sopenharmony_ci if (oob_done) 104862306a36Sopenharmony_ci sas_phy->oob_mode = SAS_OOB_MODE; 104962306a36Sopenharmony_ci phy->frame_rcvd_size = 105062306a36Sopenharmony_ci sizeof(struct sas_identify_frame); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci memcpy(sas_phy->attached_sas_addr, 105362306a36Sopenharmony_ci &phy->att_dev_sas_addr, SAS_ADDR_SIZE); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (MVS_CHIP_DISP->phy_work_around) 105662306a36Sopenharmony_ci MVS_CHIP_DISP->phy_work_around(mvi, i); 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci mv_dprintk("phy %d attach dev info is %x\n", 105962306a36Sopenharmony_ci i + mvi->id * mvi->chip->n_phy, phy->att_dev_info); 106062306a36Sopenharmony_ci mv_dprintk("phy %d attach sas addr is %llx\n", 106162306a36Sopenharmony_ci i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr); 106262306a36Sopenharmony_ciout_done: 106362306a36Sopenharmony_ci if (get_st) 106462306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct sas_ha_struct *sas_ha = sas_phy->ha; 107062306a36Sopenharmony_ci struct mvs_info *mvi = NULL; int i = 0, hi; 107162306a36Sopenharmony_ci struct mvs_phy *phy = sas_phy->lldd_phy; 107262306a36Sopenharmony_ci struct asd_sas_port *sas_port = sas_phy->port; 107362306a36Sopenharmony_ci struct mvs_port *port; 107462306a36Sopenharmony_ci unsigned long flags = 0; 107562306a36Sopenharmony_ci if (!sas_port) 107662306a36Sopenharmony_ci return; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci while (sas_ha->sas_phy[i]) { 107962306a36Sopenharmony_ci if (sas_ha->sas_phy[i] == sas_phy) 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci i++; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy; 108462306a36Sopenharmony_ci mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi]; 108562306a36Sopenharmony_ci if (i >= mvi->chip->n_phy) 108662306a36Sopenharmony_ci port = &mvi->port[i - mvi->chip->n_phy]; 108762306a36Sopenharmony_ci else 108862306a36Sopenharmony_ci port = &mvi->port[i]; 108962306a36Sopenharmony_ci if (lock) 109062306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 109162306a36Sopenharmony_ci port->port_attached = 1; 109262306a36Sopenharmony_ci phy->port = port; 109362306a36Sopenharmony_ci sas_port->lldd_port = port; 109462306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 109562306a36Sopenharmony_ci port->wide_port_phymap = sas_port->phy_mask; 109662306a36Sopenharmony_ci mv_printk("set wide port phy map %x\n", sas_port->phy_mask); 109762306a36Sopenharmony_ci mvs_update_wideport(mvi, sas_phy->id); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* direct attached SAS device */ 110062306a36Sopenharmony_ci if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { 110162306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 110262306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x04); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci if (lock) 110662306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct domain_device *dev; 111262306a36Sopenharmony_ci struct mvs_phy *phy = sas_phy->lldd_phy; 111362306a36Sopenharmony_ci struct mvs_info *mvi = phy->mvi; 111462306a36Sopenharmony_ci struct asd_sas_port *port = sas_phy->port; 111562306a36Sopenharmony_ci int phy_no = 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci while (phy != &mvi->phy[phy_no]) { 111862306a36Sopenharmony_ci phy_no++; 111962306a36Sopenharmony_ci if (phy_no >= MVS_MAX_PHYS) 112062306a36Sopenharmony_ci return; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci list_for_each_entry(dev, &port->dev_list, dev_list_node) 112362306a36Sopenharmony_ci mvs_do_release_task(phy->mvi, phy_no, dev); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_civoid mvs_port_formed(struct asd_sas_phy *sas_phy) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci mvs_port_notify_formed(sas_phy, 1); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_civoid mvs_port_deformed(struct asd_sas_phy *sas_phy) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci mvs_port_notify_deformed(sas_phy, 1); 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci u32 dev; 114162306a36Sopenharmony_ci for (dev = 0; dev < MVS_MAX_DEVICES; dev++) { 114262306a36Sopenharmony_ci if (mvi->devices[dev].dev_type == SAS_PHY_UNUSED) { 114362306a36Sopenharmony_ci mvi->devices[dev].device_id = dev; 114462306a36Sopenharmony_ci return &mvi->devices[dev]; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (dev == MVS_MAX_DEVICES) 114962306a36Sopenharmony_ci mv_printk("max support %d devices, ignore ..\n", 115062306a36Sopenharmony_ci MVS_MAX_DEVICES); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci return NULL; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic void mvs_free_dev(struct mvs_device *mvi_dev) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci u32 id = mvi_dev->device_id; 115862306a36Sopenharmony_ci memset(mvi_dev, 0, sizeof(*mvi_dev)); 115962306a36Sopenharmony_ci mvi_dev->device_id = id; 116062306a36Sopenharmony_ci mvi_dev->dev_type = SAS_PHY_UNUSED; 116162306a36Sopenharmony_ci mvi_dev->dev_status = MVS_DEV_NORMAL; 116262306a36Sopenharmony_ci mvi_dev->taskfileset = MVS_ID_NOT_MAPPED; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic int mvs_dev_found_notify(struct domain_device *dev, int lock) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci unsigned long flags = 0; 116862306a36Sopenharmony_ci int res = 0; 116962306a36Sopenharmony_ci struct mvs_info *mvi = NULL; 117062306a36Sopenharmony_ci struct domain_device *parent_dev = dev->parent; 117162306a36Sopenharmony_ci struct mvs_device *mvi_device; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci mvi = mvs_find_dev_mvi(dev); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (lock) 117662306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci mvi_device = mvs_alloc_dev(mvi); 117962306a36Sopenharmony_ci if (!mvi_device) { 118062306a36Sopenharmony_ci res = -1; 118162306a36Sopenharmony_ci goto found_out; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci dev->lldd_dev = mvi_device; 118462306a36Sopenharmony_ci mvi_device->dev_status = MVS_DEV_NORMAL; 118562306a36Sopenharmony_ci mvi_device->dev_type = dev->dev_type; 118662306a36Sopenharmony_ci mvi_device->mvi_info = mvi; 118762306a36Sopenharmony_ci mvi_device->sas_device = dev; 118862306a36Sopenharmony_ci if (parent_dev && dev_is_expander(parent_dev->dev_type)) { 118962306a36Sopenharmony_ci int phy_id; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); 119262306a36Sopenharmony_ci if (phy_id < 0) { 119362306a36Sopenharmony_ci mv_printk("Error: no attached dev:%016llx" 119462306a36Sopenharmony_ci "at ex:%016llx.\n", 119562306a36Sopenharmony_ci SAS_ADDR(dev->sas_addr), 119662306a36Sopenharmony_ci SAS_ADDR(parent_dev->sas_addr)); 119762306a36Sopenharmony_ci res = phy_id; 119862306a36Sopenharmony_ci } else { 119962306a36Sopenharmony_ci mvi_device->attached_phy = phy_id; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cifound_out: 120462306a36Sopenharmony_ci if (lock) 120562306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 120662306a36Sopenharmony_ci return res; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ciint mvs_dev_found(struct domain_device *dev) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci return mvs_dev_found_notify(dev, 1); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic void mvs_dev_gone_notify(struct domain_device *dev) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci unsigned long flags = 0; 121762306a36Sopenharmony_ci struct mvs_device *mvi_dev = dev->lldd_dev; 121862306a36Sopenharmony_ci struct mvs_info *mvi; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (!mvi_dev) { 122162306a36Sopenharmony_ci mv_dprintk("found dev has gone.\n"); 122262306a36Sopenharmony_ci return; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci mvi = mvi_dev->mvi_info; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci mv_dprintk("found dev[%d:%x] is gone.\n", 123062306a36Sopenharmony_ci mvi_dev->device_id, mvi_dev->dev_type); 123162306a36Sopenharmony_ci mvs_release_task(mvi, dev); 123262306a36Sopenharmony_ci mvs_free_reg_set(mvi, mvi_dev); 123362306a36Sopenharmony_ci mvs_free_dev(mvi_dev); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci dev->lldd_dev = NULL; 123662306a36Sopenharmony_ci mvi_dev->sas_device = NULL; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_civoid mvs_dev_gone(struct domain_device *dev) 124362306a36Sopenharmony_ci{ 124462306a36Sopenharmony_ci mvs_dev_gone_notify(dev); 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci/* Standard mandates link reset for ATA (type 0) 124862306a36Sopenharmony_ci and hard reset for SSP (type 1) , only for RECOVERY */ 124962306a36Sopenharmony_cistatic int mvs_debug_I_T_nexus_reset(struct domain_device *dev) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci int rc; 125262306a36Sopenharmony_ci struct sas_phy *phy = sas_get_local_phy(dev); 125362306a36Sopenharmony_ci int reset_type = (dev->dev_type == SAS_SATA_DEV || 125462306a36Sopenharmony_ci (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; 125562306a36Sopenharmony_ci rc = sas_phy_reset(phy, reset_type); 125662306a36Sopenharmony_ci sas_put_local_phy(phy); 125762306a36Sopenharmony_ci msleep(2000); 125862306a36Sopenharmony_ci return rc; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci/* mandatory SAM-3 */ 126262306a36Sopenharmony_ciint mvs_lu_reset(struct domain_device *dev, u8 *lun) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci unsigned long flags; 126562306a36Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 126662306a36Sopenharmony_ci struct mvs_device * mvi_dev = dev->lldd_dev; 126762306a36Sopenharmony_ci struct mvs_info *mvi = mvi_dev->mvi_info; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci mvi_dev->dev_status = MVS_DEV_EH; 127062306a36Sopenharmony_ci rc = sas_lu_reset(dev, lun); 127162306a36Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) { 127262306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 127362306a36Sopenharmony_ci mvs_release_task(mvi, dev); 127462306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci /* If failed, fall-through I_T_Nexus reset */ 127762306a36Sopenharmony_ci mv_printk("%s for device[%x]:rc= %d\n", __func__, 127862306a36Sopenharmony_ci mvi_dev->device_id, rc); 127962306a36Sopenharmony_ci return rc; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ciint mvs_I_T_nexus_reset(struct domain_device *dev) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci unsigned long flags; 128562306a36Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 128662306a36Sopenharmony_ci struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 128762306a36Sopenharmony_ci struct mvs_info *mvi = mvi_dev->mvi_info; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (mvi_dev->dev_status != MVS_DEV_EH) 129062306a36Sopenharmony_ci return TMF_RESP_FUNC_COMPLETE; 129162306a36Sopenharmony_ci else 129262306a36Sopenharmony_ci mvi_dev->dev_status = MVS_DEV_NORMAL; 129362306a36Sopenharmony_ci rc = mvs_debug_I_T_nexus_reset(dev); 129462306a36Sopenharmony_ci mv_printk("%s for device[%x]:rc= %d\n", 129562306a36Sopenharmony_ci __func__, mvi_dev->device_id, rc); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 129862306a36Sopenharmony_ci mvs_release_task(mvi, dev); 129962306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci return rc; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci/* optional SAM-3 */ 130462306a36Sopenharmony_ciint mvs_query_task(struct sas_task *task) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci u32 tag; 130762306a36Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 131062306a36Sopenharmony_ci struct domain_device *dev = task->dev; 131162306a36Sopenharmony_ci struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 131262306a36Sopenharmony_ci struct mvs_info *mvi = mvi_dev->mvi_info; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci rc = mvs_find_tag(mvi, task, &tag); 131562306a36Sopenharmony_ci if (rc == 0) { 131662306a36Sopenharmony_ci rc = TMF_RESP_FUNC_FAILED; 131762306a36Sopenharmony_ci return rc; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci rc = sas_query_task(task, tag); 132162306a36Sopenharmony_ci switch (rc) { 132262306a36Sopenharmony_ci /* The task is still in Lun, release it then */ 132362306a36Sopenharmony_ci case TMF_RESP_FUNC_SUCC: 132462306a36Sopenharmony_ci /* The task is not in Lun or failed, reset the phy */ 132562306a36Sopenharmony_ci case TMF_RESP_FUNC_FAILED: 132662306a36Sopenharmony_ci case TMF_RESP_FUNC_COMPLETE: 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci mv_printk("%s:rc= %d\n", __func__, rc); 133162306a36Sopenharmony_ci return rc; 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci/* mandatory SAM-3, still need free task/slot info */ 133562306a36Sopenharmony_ciint mvs_abort_task(struct sas_task *task) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct domain_device *dev = task->dev; 133862306a36Sopenharmony_ci struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 133962306a36Sopenharmony_ci struct mvs_info *mvi; 134062306a36Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 134162306a36Sopenharmony_ci unsigned long flags; 134262306a36Sopenharmony_ci u32 tag; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (!mvi_dev) { 134562306a36Sopenharmony_ci mv_printk("Device has removed\n"); 134662306a36Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci mvi = mvi_dev->mvi_info; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 135262306a36Sopenharmony_ci if (task->task_state_flags & SAS_TASK_STATE_DONE) { 135362306a36Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 135462306a36Sopenharmony_ci rc = TMF_RESP_FUNC_COMPLETE; 135562306a36Sopenharmony_ci goto out; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 135862306a36Sopenharmony_ci mvi_dev->dev_status = MVS_DEV_EH; 135962306a36Sopenharmony_ci if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 136062306a36Sopenharmony_ci rc = mvs_find_tag(mvi, task, &tag); 136162306a36Sopenharmony_ci if (rc == 0) { 136262306a36Sopenharmony_ci mv_printk("No such tag in %s\n", __func__); 136362306a36Sopenharmony_ci rc = TMF_RESP_FUNC_FAILED; 136462306a36Sopenharmony_ci return rc; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci rc = sas_abort_task(task, tag); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci /* if successful, clear the task and callback forwards.*/ 137062306a36Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) { 137162306a36Sopenharmony_ci u32 slot_no; 137262306a36Sopenharmony_ci struct mvs_slot_info *slot; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (task->lldd_task) { 137562306a36Sopenharmony_ci slot = task->lldd_task; 137662306a36Sopenharmony_ci slot_no = (u32) (slot - mvi->slot_info); 137762306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 137862306a36Sopenharmony_ci mvs_slot_complete(mvi, slot_no, 1); 137962306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci } else if (task->task_proto & SAS_PROTOCOL_SATA || 138462306a36Sopenharmony_ci task->task_proto & SAS_PROTOCOL_STP) { 138562306a36Sopenharmony_ci if (SAS_SATA_DEV == dev->dev_type) { 138662306a36Sopenharmony_ci struct mvs_slot_info *slot = task->lldd_task; 138762306a36Sopenharmony_ci u32 slot_idx = (u32)(slot - mvi->slot_info); 138862306a36Sopenharmony_ci mv_dprintk("mvs_abort_task() mvi=%p task=%p " 138962306a36Sopenharmony_ci "slot=%p slot_idx=x%x\n", 139062306a36Sopenharmony_ci mvi, task, slot, slot_idx); 139162306a36Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_ABORTED; 139262306a36Sopenharmony_ci mvs_slot_task_free(mvi, task, slot, slot_idx); 139362306a36Sopenharmony_ci rc = TMF_RESP_FUNC_COMPLETE; 139462306a36Sopenharmony_ci goto out; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ciout: 139962306a36Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 140062306a36Sopenharmony_ci mv_printk("%s:rc= %d\n", __func__, rc); 140162306a36Sopenharmony_ci return rc; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, 140562306a36Sopenharmony_ci u32 slot_idx, int err) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci struct mvs_device *mvi_dev = task->dev->lldd_dev; 140862306a36Sopenharmony_ci struct task_status_struct *tstat = &task->task_status; 140962306a36Sopenharmony_ci struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; 141062306a36Sopenharmony_ci int stat = SAM_STAT_GOOD; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci resp->frame_len = sizeof(struct dev_to_host_fis); 141462306a36Sopenharmony_ci memcpy(&resp->ending_fis[0], 141562306a36Sopenharmony_ci SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), 141662306a36Sopenharmony_ci sizeof(struct dev_to_host_fis)); 141762306a36Sopenharmony_ci tstat->buf_valid_size = sizeof(*resp); 141862306a36Sopenharmony_ci if (unlikely(err)) { 141962306a36Sopenharmony_ci if (unlikely(err & CMD_ISS_STPD)) 142062306a36Sopenharmony_ci stat = SAS_OPEN_REJECT; 142162306a36Sopenharmony_ci else 142262306a36Sopenharmony_ci stat = SAS_PROTO_RESPONSE; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci return stat; 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic void mvs_set_sense(u8 *buffer, int len, int d_sense, 142962306a36Sopenharmony_ci int key, int asc, int ascq) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci memset(buffer, 0, len); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (d_sense) { 143462306a36Sopenharmony_ci /* Descriptor format */ 143562306a36Sopenharmony_ci if (len < 4) { 143662306a36Sopenharmony_ci mv_printk("Length %d of sense buffer too small to " 143762306a36Sopenharmony_ci "fit sense %x:%x:%x", len, key, asc, ascq); 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci buffer[0] = 0x72; /* Response Code */ 144162306a36Sopenharmony_ci if (len > 1) 144262306a36Sopenharmony_ci buffer[1] = key; /* Sense Key */ 144362306a36Sopenharmony_ci if (len > 2) 144462306a36Sopenharmony_ci buffer[2] = asc; /* ASC */ 144562306a36Sopenharmony_ci if (len > 3) 144662306a36Sopenharmony_ci buffer[3] = ascq; /* ASCQ */ 144762306a36Sopenharmony_ci } else { 144862306a36Sopenharmony_ci if (len < 14) { 144962306a36Sopenharmony_ci mv_printk("Length %d of sense buffer too small to " 145062306a36Sopenharmony_ci "fit sense %x:%x:%x", len, key, asc, ascq); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci buffer[0] = 0x70; /* Response Code */ 145462306a36Sopenharmony_ci if (len > 2) 145562306a36Sopenharmony_ci buffer[2] = key; /* Sense Key */ 145662306a36Sopenharmony_ci if (len > 7) 145762306a36Sopenharmony_ci buffer[7] = 0x0a; /* Additional Sense Length */ 145862306a36Sopenharmony_ci if (len > 12) 145962306a36Sopenharmony_ci buffer[12] = asc; /* ASC */ 146062306a36Sopenharmony_ci if (len > 13) 146162306a36Sopenharmony_ci buffer[13] = ascq; /* ASCQ */ 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci return; 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu, 146862306a36Sopenharmony_ci u8 key, u8 asc, u8 asc_q) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci iu->datapres = SAS_DATAPRES_SENSE_DATA; 147162306a36Sopenharmony_ci iu->response_data_len = 0; 147262306a36Sopenharmony_ci iu->sense_data_len = 17; 147362306a36Sopenharmony_ci iu->status = 02; 147462306a36Sopenharmony_ci mvs_set_sense(iu->sense_data, 17, 0, 147562306a36Sopenharmony_ci key, asc, asc_q); 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, 147962306a36Sopenharmony_ci u32 slot_idx) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 148262306a36Sopenharmony_ci int stat; 148362306a36Sopenharmony_ci u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response); 148462306a36Sopenharmony_ci u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1)); 148562306a36Sopenharmony_ci u32 tfs = 0; 148662306a36Sopenharmony_ci enum mvs_port_type type = PORT_TYPE_SAS; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (err_dw0 & CMD_ISS_STPD) 148962306a36Sopenharmony_ci MVS_CHIP_DISP->issue_stop(mvi, type, tfs); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci MVS_CHIP_DISP->command_active(mvi, slot_idx); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci stat = SAM_STAT_CHECK_CONDITION; 149462306a36Sopenharmony_ci switch (task->task_proto) { 149562306a36Sopenharmony_ci case SAS_PROTOCOL_SSP: 149662306a36Sopenharmony_ci { 149762306a36Sopenharmony_ci stat = SAS_ABORTED_TASK; 149862306a36Sopenharmony_ci if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) { 149962306a36Sopenharmony_ci struct ssp_response_iu *iu = slot->response + 150062306a36Sopenharmony_ci sizeof(struct mvs_err_info); 150162306a36Sopenharmony_ci mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01); 150262306a36Sopenharmony_ci sas_ssp_task_response(mvi->dev, task, iu); 150362306a36Sopenharmony_ci stat = SAM_STAT_CHECK_CONDITION; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci if (err_dw1 & bit(31)) 150662306a36Sopenharmony_ci mv_printk("reuse same slot, retry command.\n"); 150762306a36Sopenharmony_ci break; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci case SAS_PROTOCOL_SMP: 151062306a36Sopenharmony_ci stat = SAM_STAT_CHECK_CONDITION; 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci case SAS_PROTOCOL_SATA: 151462306a36Sopenharmony_ci case SAS_PROTOCOL_STP: 151562306a36Sopenharmony_ci case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 151662306a36Sopenharmony_ci { 151762306a36Sopenharmony_ci task->ata_task.use_ncq = 0; 151862306a36Sopenharmony_ci stat = SAS_PROTO_RESPONSE; 151962306a36Sopenharmony_ci mvs_sata_done(mvi, task, slot_idx, err_dw0); 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci break; 152262306a36Sopenharmony_ci default: 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci return stat; 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ciint mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 153262306a36Sopenharmony_ci struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 153362306a36Sopenharmony_ci struct sas_task *task = slot->task; 153462306a36Sopenharmony_ci struct mvs_device *mvi_dev = NULL; 153562306a36Sopenharmony_ci struct task_status_struct *tstat; 153662306a36Sopenharmony_ci struct domain_device *dev; 153762306a36Sopenharmony_ci u32 aborted; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci void *to; 154062306a36Sopenharmony_ci enum exec_status sts; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (unlikely(!task || !task->lldd_task || !task->dev)) 154362306a36Sopenharmony_ci return -1; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci tstat = &task->task_status; 154662306a36Sopenharmony_ci dev = task->dev; 154762306a36Sopenharmony_ci mvi_dev = dev->lldd_dev; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci spin_lock(&task->task_state_lock); 155062306a36Sopenharmony_ci task->task_state_flags &= ~SAS_TASK_STATE_PENDING; 155162306a36Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_DONE; 155262306a36Sopenharmony_ci /* race condition*/ 155362306a36Sopenharmony_ci aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; 155462306a36Sopenharmony_ci spin_unlock(&task->task_state_lock); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci memset(tstat, 0, sizeof(*tstat)); 155762306a36Sopenharmony_ci tstat->resp = SAS_TASK_COMPLETE; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (unlikely(aborted)) { 156062306a36Sopenharmony_ci tstat->stat = SAS_ABORTED_TASK; 156162306a36Sopenharmony_ci if (mvi_dev && mvi_dev->running_req) 156262306a36Sopenharmony_ci mvi_dev->running_req--; 156362306a36Sopenharmony_ci if (sas_protocol_ata(task->task_proto)) 156462306a36Sopenharmony_ci mvs_free_reg_set(mvi, mvi_dev); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci mvs_slot_task_free(mvi, task, slot, slot_idx); 156762306a36Sopenharmony_ci return -1; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* when no device attaching, go ahead and complete by error handling*/ 157162306a36Sopenharmony_ci if (unlikely(!mvi_dev || flags)) { 157262306a36Sopenharmony_ci if (!mvi_dev) 157362306a36Sopenharmony_ci mv_dprintk("port has not device.\n"); 157462306a36Sopenharmony_ci tstat->stat = SAS_PHY_DOWN; 157562306a36Sopenharmony_ci goto out; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* 157962306a36Sopenharmony_ci * error info record present; slot->response is 32 bit aligned but may 158062306a36Sopenharmony_ci * not be 64 bit aligned, so check for zero in two 32 bit reads 158162306a36Sopenharmony_ci */ 158262306a36Sopenharmony_ci if (unlikely((rx_desc & RXQ_ERR) 158362306a36Sopenharmony_ci && (*((u32 *)slot->response) 158462306a36Sopenharmony_ci || *(((u32 *)slot->response) + 1)))) { 158562306a36Sopenharmony_ci mv_dprintk("port %d slot %d rx_desc %X has error info" 158662306a36Sopenharmony_ci "%016llX.\n", slot->port->sas_port.id, slot_idx, 158762306a36Sopenharmony_ci rx_desc, get_unaligned_le64(slot->response)); 158862306a36Sopenharmony_ci tstat->stat = mvs_slot_err(mvi, task, slot_idx); 158962306a36Sopenharmony_ci tstat->resp = SAS_TASK_COMPLETE; 159062306a36Sopenharmony_ci goto out; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci switch (task->task_proto) { 159462306a36Sopenharmony_ci case SAS_PROTOCOL_SSP: 159562306a36Sopenharmony_ci /* hw says status == 0, datapres == 0 */ 159662306a36Sopenharmony_ci if (rx_desc & RXQ_GOOD) { 159762306a36Sopenharmony_ci tstat->stat = SAS_SAM_STAT_GOOD; 159862306a36Sopenharmony_ci tstat->resp = SAS_TASK_COMPLETE; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci /* response frame present */ 160162306a36Sopenharmony_ci else if (rx_desc & RXQ_RSP) { 160262306a36Sopenharmony_ci struct ssp_response_iu *iu = slot->response + 160362306a36Sopenharmony_ci sizeof(struct mvs_err_info); 160462306a36Sopenharmony_ci sas_ssp_task_response(mvi->dev, task, iu); 160562306a36Sopenharmony_ci } else 160662306a36Sopenharmony_ci tstat->stat = SAS_SAM_STAT_CHECK_CONDITION; 160762306a36Sopenharmony_ci break; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci case SAS_PROTOCOL_SMP: { 161062306a36Sopenharmony_ci struct scatterlist *sg_resp = &task->smp_task.smp_resp; 161162306a36Sopenharmony_ci tstat->stat = SAS_SAM_STAT_GOOD; 161262306a36Sopenharmony_ci to = kmap_atomic(sg_page(sg_resp)); 161362306a36Sopenharmony_ci memcpy(to + sg_resp->offset, 161462306a36Sopenharmony_ci slot->response + sizeof(struct mvs_err_info), 161562306a36Sopenharmony_ci sg_dma_len(sg_resp)); 161662306a36Sopenharmony_ci kunmap_atomic(to); 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci case SAS_PROTOCOL_SATA: 162162306a36Sopenharmony_ci case SAS_PROTOCOL_STP: 162262306a36Sopenharmony_ci case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { 162362306a36Sopenharmony_ci tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); 162462306a36Sopenharmony_ci break; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci default: 162862306a36Sopenharmony_ci tstat->stat = SAS_SAM_STAT_CHECK_CONDITION; 162962306a36Sopenharmony_ci break; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci if (!slot->port->port_attached) { 163262306a36Sopenharmony_ci mv_dprintk("port %d has removed.\n", slot->port->sas_port.id); 163362306a36Sopenharmony_ci tstat->stat = SAS_PHY_DOWN; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ciout: 163862306a36Sopenharmony_ci if (mvi_dev && mvi_dev->running_req) { 163962306a36Sopenharmony_ci mvi_dev->running_req--; 164062306a36Sopenharmony_ci if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req) 164162306a36Sopenharmony_ci mvs_free_reg_set(mvi, mvi_dev); 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci mvs_slot_task_free(mvi, task, slot, slot_idx); 164462306a36Sopenharmony_ci sts = tstat->stat; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci spin_unlock(&mvi->lock); 164762306a36Sopenharmony_ci if (task->task_done) 164862306a36Sopenharmony_ci task->task_done(task); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci spin_lock(&mvi->lock); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci return sts; 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_civoid mvs_do_release_task(struct mvs_info *mvi, 165662306a36Sopenharmony_ci int phy_no, struct domain_device *dev) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci u32 slot_idx; 165962306a36Sopenharmony_ci struct mvs_phy *phy; 166062306a36Sopenharmony_ci struct mvs_port *port; 166162306a36Sopenharmony_ci struct mvs_slot_info *slot, *slot2; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci phy = &mvi->phy[phy_no]; 166462306a36Sopenharmony_ci port = phy->port; 166562306a36Sopenharmony_ci if (!port) 166662306a36Sopenharmony_ci return; 166762306a36Sopenharmony_ci /* clean cmpl queue in case request is already finished */ 166862306a36Sopenharmony_ci mvs_int_rx(mvi, false); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci list_for_each_entry_safe(slot, slot2, &port->list, entry) { 167362306a36Sopenharmony_ci struct sas_task *task; 167462306a36Sopenharmony_ci slot_idx = (u32) (slot - mvi->slot_info); 167562306a36Sopenharmony_ci task = slot->task; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (dev && task->dev != dev) 167862306a36Sopenharmony_ci continue; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci mv_printk("Release slot [%x] tag[%x], task [%p]:\n", 168162306a36Sopenharmony_ci slot_idx, slot->slot_tag, task); 168262306a36Sopenharmony_ci MVS_CHIP_DISP->command_active(mvi, slot_idx); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci mvs_slot_complete(mvi, slot_idx, 1); 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_civoid mvs_release_task(struct mvs_info *mvi, 168962306a36Sopenharmony_ci struct domain_device *dev) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci int i, phyno[WIDE_PORT_MAX_PHY], num; 169262306a36Sopenharmony_ci num = mvs_find_dev_phyno(dev, phyno); 169362306a36Sopenharmony_ci for (i = 0; i < num; i++) 169462306a36Sopenharmony_ci mvs_do_release_task(mvi, phyno[i], dev); 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cistatic void mvs_phy_disconnected(struct mvs_phy *phy) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci phy->phy_attached = 0; 170062306a36Sopenharmony_ci phy->att_dev_info = 0; 170162306a36Sopenharmony_ci phy->att_dev_sas_addr = 0; 170262306a36Sopenharmony_ci} 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic void mvs_work_queue(struct work_struct *work) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct delayed_work *dw = container_of(work, struct delayed_work, work); 170762306a36Sopenharmony_ci struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); 170862306a36Sopenharmony_ci struct mvs_info *mvi = mwq->mvi; 170962306a36Sopenharmony_ci unsigned long flags; 171062306a36Sopenharmony_ci u32 phy_no = (unsigned long) mwq->data; 171162306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[phy_no]; 171262306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci spin_lock_irqsave(&mvi->lock, flags); 171562306a36Sopenharmony_ci if (mwq->handler & PHY_PLUG_EVENT) { 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci if (phy->phy_event & PHY_PLUG_OUT) { 171862306a36Sopenharmony_ci u32 tmp; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no); 172162306a36Sopenharmony_ci phy->phy_event &= ~PHY_PLUG_OUT; 172262306a36Sopenharmony_ci if (!(tmp & PHY_READY_MASK)) { 172362306a36Sopenharmony_ci sas_phy_disconnected(sas_phy); 172462306a36Sopenharmony_ci mvs_phy_disconnected(phy); 172562306a36Sopenharmony_ci sas_notify_phy_event(sas_phy, 172662306a36Sopenharmony_ci PHYE_LOSS_OF_SIGNAL, GFP_ATOMIC); 172762306a36Sopenharmony_ci mv_dprintk("phy%d Removed Device\n", phy_no); 172862306a36Sopenharmony_ci } else { 172962306a36Sopenharmony_ci MVS_CHIP_DISP->detect_porttype(mvi, phy_no); 173062306a36Sopenharmony_ci mvs_update_phyinfo(mvi, phy_no, 1); 173162306a36Sopenharmony_ci mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC); 173262306a36Sopenharmony_ci mvs_port_notify_formed(sas_phy, 0); 173362306a36Sopenharmony_ci mv_dprintk("phy%d Attached Device\n", phy_no); 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci } else if (mwq->handler & EXP_BRCT_CHG) { 173762306a36Sopenharmony_ci phy->phy_event &= ~EXP_BRCT_CHG; 173862306a36Sopenharmony_ci sas_notify_port_event(sas_phy, 173962306a36Sopenharmony_ci PORTE_BROADCAST_RCVD, GFP_ATOMIC); 174062306a36Sopenharmony_ci mv_dprintk("phy%d Got Broadcast Change\n", phy_no); 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci list_del(&mwq->entry); 174362306a36Sopenharmony_ci spin_unlock_irqrestore(&mvi->lock, flags); 174462306a36Sopenharmony_ci kfree(mwq); 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_cistatic int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci struct mvs_wq *mwq; 175062306a36Sopenharmony_ci int ret = 0; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC); 175362306a36Sopenharmony_ci if (mwq) { 175462306a36Sopenharmony_ci mwq->mvi = mvi; 175562306a36Sopenharmony_ci mwq->data = data; 175662306a36Sopenharmony_ci mwq->handler = handler; 175762306a36Sopenharmony_ci MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq); 175862306a36Sopenharmony_ci list_add_tail(&mwq->entry, &mvi->wq_list); 175962306a36Sopenharmony_ci schedule_delayed_work(&mwq->work_q, HZ * 2); 176062306a36Sopenharmony_ci } else 176162306a36Sopenharmony_ci ret = -ENOMEM; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci return ret; 176462306a36Sopenharmony_ci} 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_cistatic void mvs_sig_time_out(struct timer_list *t) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci struct mvs_phy *phy = from_timer(phy, t, timer); 176962306a36Sopenharmony_ci struct mvs_info *mvi = phy->mvi; 177062306a36Sopenharmony_ci u8 phy_no; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) { 177362306a36Sopenharmony_ci if (&mvi->phy[phy_no] == phy) { 177462306a36Sopenharmony_ci mv_dprintk("Get signature time out, reset phy %d\n", 177562306a36Sopenharmony_ci phy_no+mvi->id*mvi->chip->n_phy); 177662306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET); 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_civoid mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci u32 tmp; 178462306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[phy_no]; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); 178762306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); 178862306a36Sopenharmony_ci mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy, 178962306a36Sopenharmony_ci MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no)); 179062306a36Sopenharmony_ci mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy, 179162306a36Sopenharmony_ci phy->irq_status); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci /* 179462306a36Sopenharmony_ci * events is port event now , 179562306a36Sopenharmony_ci * we need check the interrupt status which belongs to per port. 179662306a36Sopenharmony_ci */ 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (phy->irq_status & PHYEV_DCDR_ERR) { 179962306a36Sopenharmony_ci mv_dprintk("phy %d STP decoding error.\n", 180062306a36Sopenharmony_ci phy_no + mvi->id*mvi->chip->n_phy); 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci if (phy->irq_status & PHYEV_POOF) { 180462306a36Sopenharmony_ci mdelay(500); 180562306a36Sopenharmony_ci if (!(phy->phy_event & PHY_PLUG_OUT)) { 180662306a36Sopenharmony_ci int dev_sata = phy->phy_type & PORT_TYPE_SATA; 180762306a36Sopenharmony_ci int ready; 180862306a36Sopenharmony_ci mvs_do_release_task(mvi, phy_no, NULL); 180962306a36Sopenharmony_ci phy->phy_event |= PHY_PLUG_OUT; 181062306a36Sopenharmony_ci MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1); 181162306a36Sopenharmony_ci mvs_handle_event(mvi, 181262306a36Sopenharmony_ci (void *)(unsigned long)phy_no, 181362306a36Sopenharmony_ci PHY_PLUG_EVENT); 181462306a36Sopenharmony_ci ready = mvs_is_phy_ready(mvi, phy_no); 181562306a36Sopenharmony_ci if (ready || dev_sata) { 181662306a36Sopenharmony_ci if (MVS_CHIP_DISP->stp_reset) 181762306a36Sopenharmony_ci MVS_CHIP_DISP->stp_reset(mvi, 181862306a36Sopenharmony_ci phy_no); 181962306a36Sopenharmony_ci else 182062306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, 182162306a36Sopenharmony_ci phy_no, MVS_SOFT_RESET); 182262306a36Sopenharmony_ci return; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (phy->irq_status & PHYEV_COMWAKE) { 182862306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no); 182962306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no, 183062306a36Sopenharmony_ci tmp | PHYEV_SIG_FIS); 183162306a36Sopenharmony_ci if (phy->timer.function == NULL) { 183262306a36Sopenharmony_ci phy->timer.function = mvs_sig_time_out; 183362306a36Sopenharmony_ci phy->timer.expires = jiffies + 5*HZ; 183462306a36Sopenharmony_ci add_timer(&phy->timer); 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { 183862306a36Sopenharmony_ci phy->phy_status = mvs_is_phy_ready(mvi, phy_no); 183962306a36Sopenharmony_ci mv_dprintk("notify plug in on phy[%d]\n", phy_no); 184062306a36Sopenharmony_ci if (phy->phy_status) { 184162306a36Sopenharmony_ci mdelay(10); 184262306a36Sopenharmony_ci MVS_CHIP_DISP->detect_porttype(mvi, phy_no); 184362306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SATA) { 184462306a36Sopenharmony_ci tmp = MVS_CHIP_DISP->read_port_irq_mask( 184562306a36Sopenharmony_ci mvi, phy_no); 184662306a36Sopenharmony_ci tmp &= ~PHYEV_SIG_FIS; 184762306a36Sopenharmony_ci MVS_CHIP_DISP->write_port_irq_mask(mvi, 184862306a36Sopenharmony_ci phy_no, tmp); 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci mvs_update_phyinfo(mvi, phy_no, 0); 185162306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 185262306a36Sopenharmony_ci MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE); 185362306a36Sopenharmony_ci mdelay(10); 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC); 185762306a36Sopenharmony_ci /* whether driver is going to handle hot plug */ 185862306a36Sopenharmony_ci if (phy->phy_event & PHY_PLUG_OUT) { 185962306a36Sopenharmony_ci mvs_port_notify_formed(&phy->sas_phy, 0); 186062306a36Sopenharmony_ci phy->phy_event &= ~PHY_PLUG_OUT; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci } else { 186362306a36Sopenharmony_ci mv_dprintk("plugin interrupt but phy%d is gone\n", 186462306a36Sopenharmony_ci phy_no + mvi->id*mvi->chip->n_phy); 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci } else if (phy->irq_status & PHYEV_BROAD_CH) { 186762306a36Sopenharmony_ci mv_dprintk("phy %d broadcast change.\n", 186862306a36Sopenharmony_ci phy_no + mvi->id*mvi->chip->n_phy); 186962306a36Sopenharmony_ci mvs_handle_event(mvi, (void *)(unsigned long)phy_no, 187062306a36Sopenharmony_ci EXP_BRCT_CHG); 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci} 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ciint mvs_int_rx(struct mvs_info *mvi, bool self_clear) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci u32 rx_prod_idx, rx_desc; 187762306a36Sopenharmony_ci bool attn = false; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci /* the first dword in the RX ring is special: it contains 188062306a36Sopenharmony_ci * a mirror of the hardware's RX producer index, so that 188162306a36Sopenharmony_ci * we don't have to stall the CPU reading that register. 188262306a36Sopenharmony_ci * The actual RX ring is offset by one dword, due to this. 188362306a36Sopenharmony_ci */ 188462306a36Sopenharmony_ci rx_prod_idx = mvi->rx_cons; 188562306a36Sopenharmony_ci mvi->rx_cons = le32_to_cpu(mvi->rx[0]); 188662306a36Sopenharmony_ci if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ 188762306a36Sopenharmony_ci return 0; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci /* The CMPL_Q may come late, read from register and try again 189062306a36Sopenharmony_ci * note: if coalescing is enabled, 189162306a36Sopenharmony_ci * it will need to read from register every time for sure 189262306a36Sopenharmony_ci */ 189362306a36Sopenharmony_ci if (unlikely(mvi->rx_cons == rx_prod_idx)) 189462306a36Sopenharmony_ci mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci if (mvi->rx_cons == rx_prod_idx) 189762306a36Sopenharmony_ci return 0; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci while (mvi->rx_cons != rx_prod_idx) { 190062306a36Sopenharmony_ci /* increment our internal RX consumer pointer */ 190162306a36Sopenharmony_ci rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); 190262306a36Sopenharmony_ci rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci if (likely(rx_desc & RXQ_DONE)) 190562306a36Sopenharmony_ci mvs_slot_complete(mvi, rx_desc, 0); 190662306a36Sopenharmony_ci if (rx_desc & RXQ_ATTN) { 190762306a36Sopenharmony_ci attn = true; 190862306a36Sopenharmony_ci } else if (rx_desc & RXQ_ERR) { 190962306a36Sopenharmony_ci if (!(rx_desc & RXQ_DONE)) 191062306a36Sopenharmony_ci mvs_slot_complete(mvi, rx_desc, 0); 191162306a36Sopenharmony_ci } else if (rx_desc & RXQ_SLOT_RESET) { 191262306a36Sopenharmony_ci mvs_slot_free(mvi, rx_desc); 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (attn && self_clear) 191762306a36Sopenharmony_ci MVS_CHIP_DISP->int_full(mvi); 191862306a36Sopenharmony_ci return 0; 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ciint mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index, 192262306a36Sopenharmony_ci u8 reg_count, u8 *write_data) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci struct mvs_prv_info *mvs_prv = sha->lldd_ha; 192562306a36Sopenharmony_ci struct mvs_info *mvi = mvs_prv->mvi[0]; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (MVS_CHIP_DISP->gpio_write) { 192862306a36Sopenharmony_ci return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type, 192962306a36Sopenharmony_ci reg_index, reg_count, write_data); 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci return -ENOSYS; 193362306a36Sopenharmony_ci} 1934