162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright 2014 Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/errno.h> 562306a36Sopenharmony_ci#include <linux/mempool.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "snic_disc.h" 1062306a36Sopenharmony_ci#include "snic.h" 1162306a36Sopenharmony_ci#include "snic_io.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* snic target types */ 1562306a36Sopenharmony_cistatic const char * const snic_tgt_type_str[] = { 1662306a36Sopenharmony_ci [SNIC_TGT_DAS] = "DAS", 1762306a36Sopenharmony_ci [SNIC_TGT_SAN] = "SAN", 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic inline const char * 2162306a36Sopenharmony_cisnic_tgt_type_to_str(int typ) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return ((typ > SNIC_TGT_NONE && typ <= SNIC_TGT_SAN) ? 2462306a36Sopenharmony_ci snic_tgt_type_str[typ] : "Unknown"); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const char * const snic_tgt_state_str[] = { 2862306a36Sopenharmony_ci [SNIC_TGT_STAT_INIT] = "INIT", 2962306a36Sopenharmony_ci [SNIC_TGT_STAT_ONLINE] = "ONLINE", 3062306a36Sopenharmony_ci [SNIC_TGT_STAT_OFFLINE] = "OFFLINE", 3162306a36Sopenharmony_ci [SNIC_TGT_STAT_DEL] = "DELETION IN PROGRESS", 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciconst char * 3562306a36Sopenharmony_cisnic_tgt_state_to_str(int state) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return ((state >= SNIC_TGT_STAT_INIT && state <= SNIC_TGT_STAT_DEL) ? 3862306a36Sopenharmony_ci snic_tgt_state_str[state] : "UNKNOWN"); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Initiate report_tgt req desc 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic void 4562306a36Sopenharmony_cisnic_report_tgt_init(struct snic_host_req *req, u32 hid, u8 *buf, u32 len, 4662306a36Sopenharmony_ci dma_addr_t rsp_buf_pa, ulong ctx) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct snic_sg_desc *sgd = NULL; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci snic_io_hdr_enc(&req->hdr, SNIC_REQ_REPORT_TGTS, 0, SCSI_NO_TAG, hid, 5262306a36Sopenharmony_ci 1, ctx); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci req->u.rpt_tgts.sg_cnt = cpu_to_le16(1); 5562306a36Sopenharmony_ci sgd = req_to_sgl(req); 5662306a36Sopenharmony_ci sgd[0].addr = cpu_to_le64(rsp_buf_pa); 5762306a36Sopenharmony_ci sgd[0].len = cpu_to_le32(len); 5862306a36Sopenharmony_ci sgd[0]._resvd = 0; 5962306a36Sopenharmony_ci req->u.rpt_tgts.sg_addr = cpu_to_le64((ulong)sgd); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * snic_queue_report_tgt_req: Queues report target request. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cistatic int 6662306a36Sopenharmony_cisnic_queue_report_tgt_req(struct snic *snic) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct snic_req_info *rqi = NULL; 6962306a36Sopenharmony_ci u32 ntgts, buf_len = 0; 7062306a36Sopenharmony_ci u8 *buf = NULL; 7162306a36Sopenharmony_ci dma_addr_t pa = 0; 7262306a36Sopenharmony_ci int ret = 0; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci rqi = snic_req_init(snic, 1); 7562306a36Sopenharmony_ci if (!rqi) { 7662306a36Sopenharmony_ci ret = -ENOMEM; 7762306a36Sopenharmony_ci goto error; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (snic->fwinfo.max_tgts) 8162306a36Sopenharmony_ci ntgts = min_t(u32, snic->fwinfo.max_tgts, snic->shost->max_id); 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci ntgts = snic->shost->max_id; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Allocate Response Buffer */ 8662306a36Sopenharmony_ci SNIC_BUG_ON(ntgts == 0); 8762306a36Sopenharmony_ci buf_len = ntgts * sizeof(struct snic_tgt_id) + SNIC_SG_DESC_ALIGN; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 9062306a36Sopenharmony_ci if (!buf) { 9162306a36Sopenharmony_ci snic_req_free(snic, rqi); 9262306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "Resp Buf Alloc Failed.\n"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = -ENOMEM; 9562306a36Sopenharmony_ci goto error; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci SNIC_BUG_ON((((unsigned long)buf) % SNIC_SG_DESC_ALIGN) != 0); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci pa = dma_map_single(&snic->pdev->dev, buf, buf_len, DMA_FROM_DEVICE); 10162306a36Sopenharmony_ci if (dma_mapping_error(&snic->pdev->dev, pa)) { 10262306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 10362306a36Sopenharmony_ci "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n", 10462306a36Sopenharmony_ci buf); 10562306a36Sopenharmony_ci kfree(buf); 10662306a36Sopenharmony_ci snic_req_free(snic, rqi); 10762306a36Sopenharmony_ci ret = -EINVAL; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci goto error; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci SNIC_BUG_ON(pa == 0); 11462306a36Sopenharmony_ci rqi->sge_va = (ulong) buf; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci snic_report_tgt_init(rqi->req, 11762306a36Sopenharmony_ci snic->config.hid, 11862306a36Sopenharmony_ci buf, 11962306a36Sopenharmony_ci buf_len, 12062306a36Sopenharmony_ci pa, 12162306a36Sopenharmony_ci (ulong)rqi); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci snic_handle_untagged_req(snic, rqi); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len); 12662306a36Sopenharmony_ci if (ret) { 12762306a36Sopenharmony_ci dma_unmap_single(&snic->pdev->dev, pa, buf_len, 12862306a36Sopenharmony_ci DMA_FROM_DEVICE); 12962306a36Sopenharmony_ci kfree(buf); 13062306a36Sopenharmony_ci rqi->sge_va = 0; 13162306a36Sopenharmony_ci snic_release_untagged_req(snic, rqi); 13262306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "Queuing Report Tgts Failed.\n"); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci goto error; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci SNIC_DISC_DBG(snic->shost, "Report Targets Issued.\n"); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cierror: 14262306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 14362306a36Sopenharmony_ci "Queuing Report Targets Failed, err = %d\n", 14462306a36Sopenharmony_ci ret); 14562306a36Sopenharmony_ci return ret; 14662306a36Sopenharmony_ci} /* end of snic_queue_report_tgt_req */ 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* call into SML */ 14962306a36Sopenharmony_cistatic void 15062306a36Sopenharmony_cisnic_scsi_scan_tgt(struct work_struct *work) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct snic_tgt *tgt = container_of(work, struct snic_tgt, scan_work); 15362306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&tgt->dev); 15462306a36Sopenharmony_ci unsigned long flags; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci SNIC_HOST_INFO(shost, "Scanning Target id 0x%x\n", tgt->id); 15762306a36Sopenharmony_ci scsi_scan_target(&tgt->dev, 15862306a36Sopenharmony_ci tgt->channel, 15962306a36Sopenharmony_ci tgt->scsi_tgt_id, 16062306a36Sopenharmony_ci SCAN_WILD_CARD, 16162306a36Sopenharmony_ci SCSI_SCAN_RESCAN); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 16462306a36Sopenharmony_ci tgt->flags &= ~SNIC_TGT_SCAN_PENDING; 16562306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 16662306a36Sopenharmony_ci} /* end of snic_scsi_scan_tgt */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* 16962306a36Sopenharmony_ci * snic_tgt_lookup : 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic struct snic_tgt * 17262306a36Sopenharmony_cisnic_tgt_lookup(struct snic *snic, struct snic_tgt_id *tgtid) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct list_head *cur, *nxt; 17562306a36Sopenharmony_ci struct snic_tgt *tgt = NULL; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { 17862306a36Sopenharmony_ci tgt = list_entry(cur, struct snic_tgt, list); 17962306a36Sopenharmony_ci if (tgt->id == le32_to_cpu(tgtid->tgt_id)) 18062306a36Sopenharmony_ci return tgt; 18162306a36Sopenharmony_ci tgt = NULL; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return tgt; 18562306a36Sopenharmony_ci} /* end of snic_tgt_lookup */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * snic_tgt_dev_release : Called on dropping last ref for snic_tgt object 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_civoid 19162306a36Sopenharmony_cisnic_tgt_dev_release(struct device *dev) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct snic_tgt *tgt = dev_to_tgt(dev); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci SNIC_HOST_INFO(snic_tgt_to_shost(tgt), 19662306a36Sopenharmony_ci "Target Device ID %d (%s) Permanently Deleted.\n", 19762306a36Sopenharmony_ci tgt->id, 19862306a36Sopenharmony_ci dev_name(dev)); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci SNIC_BUG_ON(!list_empty(&tgt->list)); 20162306a36Sopenharmony_ci kfree(tgt); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* 20562306a36Sopenharmony_ci * snic_tgt_del : work function to delete snic_tgt 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_cistatic void 20862306a36Sopenharmony_cisnic_tgt_del(struct work_struct *work) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct snic_tgt *tgt = container_of(work, struct snic_tgt, del_work); 21162306a36Sopenharmony_ci struct Scsi_Host *shost = snic_tgt_to_shost(tgt); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (tgt->flags & SNIC_TGT_SCAN_PENDING) 21462306a36Sopenharmony_ci scsi_flush_work(shost); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Block IOs on child devices, stops new IOs */ 21762306a36Sopenharmony_ci scsi_block_targets(shost, &tgt->dev); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Cleanup IOs */ 22062306a36Sopenharmony_ci snic_tgt_scsi_abort_io(tgt); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Unblock IOs now, to flush if there are any. */ 22362306a36Sopenharmony_ci scsi_target_unblock(&tgt->dev, SDEV_TRANSPORT_OFFLINE); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Delete SCSI Target and sdevs */ 22662306a36Sopenharmony_ci scsi_remove_target(&tgt->dev); /* ?? */ 22762306a36Sopenharmony_ci device_del(&tgt->dev); 22862306a36Sopenharmony_ci put_device(&tgt->dev); 22962306a36Sopenharmony_ci} /* end of snic_tgt_del */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* snic_tgt_create: checks for existence of snic_tgt, if it doesn't 23262306a36Sopenharmony_ci * it creates one. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistatic struct snic_tgt * 23562306a36Sopenharmony_cisnic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct snic_tgt *tgt = NULL; 23862306a36Sopenharmony_ci unsigned long flags; 23962306a36Sopenharmony_ci int ret; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci tgt = snic_tgt_lookup(snic, tgtid); 24262306a36Sopenharmony_ci if (tgt) { 24362306a36Sopenharmony_ci /* update the information if required */ 24462306a36Sopenharmony_ci return tgt; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); 24862306a36Sopenharmony_ci if (!tgt) { 24962306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "Failure to allocate snic_tgt.\n"); 25062306a36Sopenharmony_ci ret = -ENOMEM; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return tgt; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci INIT_LIST_HEAD(&tgt->list); 25662306a36Sopenharmony_ci tgt->id = le32_to_cpu(tgtid->tgt_id); 25762306a36Sopenharmony_ci tgt->channel = 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci SNIC_BUG_ON(le16_to_cpu(tgtid->tgt_type) > SNIC_TGT_SAN); 26062306a36Sopenharmony_ci tgt->tdata.typ = le16_to_cpu(tgtid->tgt_type); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * Plugging into SML Device Tree 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci tgt->tdata.disc_id = 0; 26662306a36Sopenharmony_ci tgt->state = SNIC_TGT_STAT_INIT; 26762306a36Sopenharmony_ci device_initialize(&tgt->dev); 26862306a36Sopenharmony_ci tgt->dev.parent = get_device(&snic->shost->shost_gendev); 26962306a36Sopenharmony_ci tgt->dev.release = snic_tgt_dev_release; 27062306a36Sopenharmony_ci INIT_WORK(&tgt->scan_work, snic_scsi_scan_tgt); 27162306a36Sopenharmony_ci INIT_WORK(&tgt->del_work, snic_tgt_del); 27262306a36Sopenharmony_ci switch (tgt->tdata.typ) { 27362306a36Sopenharmony_ci case SNIC_TGT_DAS: 27462306a36Sopenharmony_ci dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", 27562306a36Sopenharmony_ci snic->shost->host_no, tgt->channel, tgt->id); 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci case SNIC_TGT_SAN: 27962306a36Sopenharmony_ci dev_set_name(&tgt->dev, "snic_san_tgt:%d:%d-%d", 28062306a36Sopenharmony_ci snic->shost->host_no, tgt->channel, tgt->id); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci default: 28462306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Target type Unknown Detected.\n"); 28562306a36Sopenharmony_ci dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", 28662306a36Sopenharmony_ci snic->shost->host_no, tgt->channel, tgt->id); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci spin_lock_irqsave(snic->shost->host_lock, flags); 29162306a36Sopenharmony_ci list_add_tail(&tgt->list, &snic->disc.tgt_list); 29262306a36Sopenharmony_ci tgt->scsi_tgt_id = snic->disc.nxt_tgt_id++; 29362306a36Sopenharmony_ci tgt->state = SNIC_TGT_STAT_ONLINE; 29462306a36Sopenharmony_ci spin_unlock_irqrestore(snic->shost->host_lock, flags); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 29762306a36Sopenharmony_ci "Tgt %d, type = %s detected. Adding..\n", 29862306a36Sopenharmony_ci tgt->id, snic_tgt_type_to_str(tgt->tdata.typ)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = device_add(&tgt->dev); 30162306a36Sopenharmony_ci if (ret) { 30262306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 30362306a36Sopenharmony_ci "Snic Tgt: device_add, with err = %d\n", 30462306a36Sopenharmony_ci ret); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci put_device(&snic->shost->shost_gendev); 30762306a36Sopenharmony_ci spin_lock_irqsave(snic->shost->host_lock, flags); 30862306a36Sopenharmony_ci list_del(&tgt->list); 30962306a36Sopenharmony_ci spin_unlock_irqrestore(snic->shost->host_lock, flags); 31062306a36Sopenharmony_ci put_device(&tgt->dev); 31162306a36Sopenharmony_ci tgt = NULL; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return tgt; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Scanning %s.\n", dev_name(&tgt->dev)); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci scsi_queue_work(snic->shost, &tgt->scan_work); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return tgt; 32162306a36Sopenharmony_ci} /* end of snic_tgt_create */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/* Handler for discovery */ 32462306a36Sopenharmony_civoid 32562306a36Sopenharmony_cisnic_handle_tgt_disc(struct work_struct *work) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct snic *snic = container_of(work, struct snic, tgt_work); 32862306a36Sopenharmony_ci struct snic_tgt_id *tgtid = NULL; 32962306a36Sopenharmony_ci struct snic_tgt *tgt = NULL; 33062306a36Sopenharmony_ci unsigned long flags; 33162306a36Sopenharmony_ci int i; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 33462306a36Sopenharmony_ci if (snic->in_remove) { 33562306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 33662306a36Sopenharmony_ci kfree(snic->disc.rtgt_info); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci mutex_lock(&snic->disc.mutex); 34362306a36Sopenharmony_ci /* Discover triggered during disc in progress */ 34462306a36Sopenharmony_ci if (snic->disc.req_cnt) { 34562306a36Sopenharmony_ci snic->disc.state = SNIC_DISC_DONE; 34662306a36Sopenharmony_ci snic->disc.req_cnt = 0; 34762306a36Sopenharmony_ci mutex_unlock(&snic->disc.mutex); 34862306a36Sopenharmony_ci kfree(snic->disc.rtgt_info); 34962306a36Sopenharmony_ci snic->disc.rtgt_info = NULL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "tgt_disc: Discovery restart.\n"); 35262306a36Sopenharmony_ci /* Start Discovery Again */ 35362306a36Sopenharmony_ci snic_disc_start(snic); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci tgtid = (struct snic_tgt_id *)snic->disc.rtgt_info; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci SNIC_BUG_ON(snic->disc.rtgt_cnt == 0 || tgtid == NULL); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (i = 0; i < snic->disc.rtgt_cnt; i++) { 36362306a36Sopenharmony_ci tgt = snic_tgt_create(snic, &tgtid[i]); 36462306a36Sopenharmony_ci if (!tgt) { 36562306a36Sopenharmony_ci int buf_sz = snic->disc.rtgt_cnt * sizeof(*tgtid); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "Failed to create tgt.\n"); 36862306a36Sopenharmony_ci snic_hex_dump("rpt_tgt_rsp", (char *)tgtid, buf_sz); 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci snic->disc.rtgt_info = NULL; 37462306a36Sopenharmony_ci snic->disc.state = SNIC_DISC_DONE; 37562306a36Sopenharmony_ci mutex_unlock(&snic->disc.mutex); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Discovery Completed.\n"); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci kfree(tgtid); 38062306a36Sopenharmony_ci} /* end of snic_handle_tgt_disc */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciint 38462306a36Sopenharmony_cisnic_report_tgt_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci u8 typ, cmpl_stat; 38862306a36Sopenharmony_ci u32 cmnd_id, hid, tgt_cnt = 0; 38962306a36Sopenharmony_ci ulong ctx; 39062306a36Sopenharmony_ci struct snic_req_info *rqi = NULL; 39162306a36Sopenharmony_ci struct snic_tgt_id *tgtid; 39262306a36Sopenharmony_ci int i, ret = 0; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci snic_io_hdr_dec(&fwreq->hdr, &typ, &cmpl_stat, &cmnd_id, &hid, &ctx); 39562306a36Sopenharmony_ci rqi = (struct snic_req_info *) ctx; 39662306a36Sopenharmony_ci tgtid = (struct snic_tgt_id *) rqi->sge_va; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci tgt_cnt = le32_to_cpu(fwreq->u.rpt_tgts_cmpl.tgt_cnt); 39962306a36Sopenharmony_ci if (tgt_cnt == 0) { 40062306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, "No Targets Found on this host.\n"); 40162306a36Sopenharmony_ci ret = 1; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci goto end; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* printing list of targets here */ 40762306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Target Count = %d\n", tgt_cnt); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci SNIC_BUG_ON(tgt_cnt > snic->fwinfo.max_tgts); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (i = 0; i < tgt_cnt; i++) 41262306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, 41362306a36Sopenharmony_ci "Tgt id = 0x%x\n", 41462306a36Sopenharmony_ci le32_to_cpu(tgtid[i].tgt_id)); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Queue work for further processing, 41862306a36Sopenharmony_ci * Response Buffer Memory is freed after creating targets 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci snic->disc.rtgt_cnt = tgt_cnt; 42162306a36Sopenharmony_ci snic->disc.rtgt_info = (u8 *) tgtid; 42262306a36Sopenharmony_ci queue_work(snic_glob->event_q, &snic->tgt_work); 42362306a36Sopenharmony_ci ret = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciend: 42662306a36Sopenharmony_ci /* Unmap Response Buffer */ 42762306a36Sopenharmony_ci snic_pci_unmap_rsp_buf(snic, rqi); 42862306a36Sopenharmony_ci if (ret) 42962306a36Sopenharmony_ci kfree(tgtid); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci rqi->sge_va = 0; 43262306a36Sopenharmony_ci snic_release_untagged_req(snic, rqi); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return ret; 43562306a36Sopenharmony_ci} /* end of snic_report_tgt_cmpl_handler */ 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* Discovery init fn */ 43862306a36Sopenharmony_civoid 43962306a36Sopenharmony_cisnic_disc_init(struct snic_disc *disc) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci INIT_LIST_HEAD(&disc->tgt_list); 44262306a36Sopenharmony_ci mutex_init(&disc->mutex); 44362306a36Sopenharmony_ci disc->disc_id = 0; 44462306a36Sopenharmony_ci disc->nxt_tgt_id = 0; 44562306a36Sopenharmony_ci disc->state = SNIC_DISC_INIT; 44662306a36Sopenharmony_ci disc->req_cnt = 0; 44762306a36Sopenharmony_ci disc->rtgt_cnt = 0; 44862306a36Sopenharmony_ci disc->rtgt_info = NULL; 44962306a36Sopenharmony_ci disc->cb = NULL; 45062306a36Sopenharmony_ci} /* end of snic_disc_init */ 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/* Discovery, uninit fn */ 45362306a36Sopenharmony_civoid 45462306a36Sopenharmony_cisnic_disc_term(struct snic *snic) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct snic_disc *disc = &snic->disc; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci mutex_lock(&disc->mutex); 45962306a36Sopenharmony_ci if (disc->req_cnt) { 46062306a36Sopenharmony_ci disc->req_cnt = 0; 46162306a36Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Terminating Discovery.\n"); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci mutex_unlock(&disc->mutex); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* 46762306a36Sopenharmony_ci * snic_disc_start: Discovery Start ... 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_ciint 47062306a36Sopenharmony_cisnic_disc_start(struct snic *snic) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct snic_disc *disc = &snic->disc; 47362306a36Sopenharmony_ci unsigned long flags; 47462306a36Sopenharmony_ci int ret = 0; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci SNIC_SCSI_DBG(snic->shost, "Discovery Start.\n"); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci spin_lock_irqsave(&snic->snic_lock, flags); 47962306a36Sopenharmony_ci if (snic->in_remove) { 48062306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 48162306a36Sopenharmony_ci SNIC_ERR("snic driver removal in progress ...\n"); 48262306a36Sopenharmony_ci ret = 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci spin_unlock_irqrestore(&snic->snic_lock, flags); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci mutex_lock(&disc->mutex); 48962306a36Sopenharmony_ci if (disc->state == SNIC_DISC_PENDING) { 49062306a36Sopenharmony_ci disc->req_cnt++; 49162306a36Sopenharmony_ci mutex_unlock(&disc->mutex); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return ret; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci disc->state = SNIC_DISC_PENDING; 49662306a36Sopenharmony_ci mutex_unlock(&disc->mutex); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ret = snic_queue_report_tgt_req(snic); 49962306a36Sopenharmony_ci if (ret) 50062306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Discovery Failed, err=%d.\n", ret); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci return ret; 50362306a36Sopenharmony_ci} /* end of snic_disc_start */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci/* 50662306a36Sopenharmony_ci * snic_disc_work : 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_civoid 50962306a36Sopenharmony_cisnic_handle_disc(struct work_struct *work) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct snic *snic = container_of(work, struct snic, disc_work); 51262306a36Sopenharmony_ci int ret = 0; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "disc_work: Discovery\n"); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ret = snic_disc_start(snic); 51762306a36Sopenharmony_ci if (ret) 51862306a36Sopenharmony_ci goto disc_err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cidisc_err: 52162306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 52262306a36Sopenharmony_ci "disc_work: Discovery Failed w/ err = %d\n", 52362306a36Sopenharmony_ci ret); 52462306a36Sopenharmony_ci} /* end of snic_disc_work */ 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * snic_tgt_del_all : cleanup all snic targets 52862306a36Sopenharmony_ci * Called on unbinding the interface 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_civoid 53162306a36Sopenharmony_cisnic_tgt_del_all(struct snic *snic) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct snic_tgt *tgt = NULL; 53462306a36Sopenharmony_ci struct list_head *cur, *nxt; 53562306a36Sopenharmony_ci unsigned long flags; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci scsi_flush_work(snic->shost); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci mutex_lock(&snic->disc.mutex); 54062306a36Sopenharmony_ci spin_lock_irqsave(snic->shost->host_lock, flags); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { 54362306a36Sopenharmony_ci tgt = list_entry(cur, struct snic_tgt, list); 54462306a36Sopenharmony_ci tgt->state = SNIC_TGT_STAT_DEL; 54562306a36Sopenharmony_ci list_del_init(&tgt->list); 54662306a36Sopenharmony_ci SNIC_HOST_INFO(snic->shost, "Tgt %d q'ing for del\n", tgt->id); 54762306a36Sopenharmony_ci queue_work(snic_glob->event_q, &tgt->del_work); 54862306a36Sopenharmony_ci tgt = NULL; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci spin_unlock_irqrestore(snic->shost->host_lock, flags); 55162306a36Sopenharmony_ci mutex_unlock(&snic->disc.mutex); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci flush_workqueue(snic_glob->event_q); 55462306a36Sopenharmony_ci} /* end of snic_tgt_del_all */ 555