15597088cSDongdong Hao // SPDX-License-Identifier: GPL-2.0
25597088cSDongdong Hao /*
35597088cSDongdong Hao * Copyright (C) 2026 LeapIO Tech Inc.
45597088cSDongdong Hao *
55597088cSDongdong Hao * LeapRAID storage and RAID controller driver.
65597088cSDongdong Hao */
75597088cSDongdong Hao #include <linux/module.h>
85597088cSDongdong Hao
95597088cSDongdong Hao #include "leapraid_func.h"
105597088cSDongdong Hao #include "leapraid.h"
115597088cSDongdong Hao
125597088cSDongdong Hao LIST_HEAD(leapraid_adapter_list);
135597088cSDongdong Hao DEFINE_SPINLOCK(leapraid_adapter_lock);
145597088cSDongdong Hao
155597088cSDongdong Hao MODULE_AUTHOR(LEAPRAID_AUTHOR);
165597088cSDongdong Hao MODULE_DESCRIPTION(LEAPRAID_DESCRIPTION);
175597088cSDongdong Hao MODULE_LICENSE("GPL");
185597088cSDongdong Hao MODULE_VERSION(LEAPRAID_DRIVER_VERSION);
195597088cSDongdong Hao
205597088cSDongdong Hao static atomic_t leapraid_ids = ATOMIC_INIT(0);
215597088cSDongdong Hao
225597088cSDongdong Hao static int open_pcie_trace = 1;
235597088cSDongdong Hao module_param(open_pcie_trace, int, 0644);
245597088cSDongdong Hao MODULE_PARM_DESC(open_pcie_trace, "Default=1(open)/0(close)");
255597088cSDongdong Hao
265597088cSDongdong Hao static int enable_mp = 1;
275597088cSDongdong Hao module_param(enable_mp, int, 0444);
285597088cSDongdong Hao MODULE_PARM_DESC(enable_mp,
295597088cSDongdong Hao "Enable multipath on target device. default=1(enable)");
305597088cSDongdong Hao
leapraid_get_sense_data(char * sense,struct sense_info * data)315597088cSDongdong Hao static inline void leapraid_get_sense_data(char *sense,
325597088cSDongdong Hao struct sense_info *data)
335597088cSDongdong Hao {
345597088cSDongdong Hao bool desc_format = (sense[0] & SCSI_SENSE_RESPONSE_CODE_MASK) >=
355597088cSDongdong Hao DESC_FORMAT_THRESHOLD;
365597088cSDongdong Hao
375597088cSDongdong Hao if (desc_format) {
385597088cSDongdong Hao data->sense_key = sense[1] & SENSE_KEY_MASK;
395597088cSDongdong Hao data->asc = sense[2];
405597088cSDongdong Hao data->ascq = sense[3];
415597088cSDongdong Hao } else {
425597088cSDongdong Hao data->sense_key = sense[2] & SENSE_KEY_MASK;
435597088cSDongdong Hao data->asc = sense[12];
445597088cSDongdong Hao data->ascq = sense[13];
455597088cSDongdong Hao }
465597088cSDongdong Hao }
475597088cSDongdong Hao
pdev_to_adapter(struct pci_dev * pdev)485597088cSDongdong Hao static struct leapraid_adapter *pdev_to_adapter(struct pci_dev *pdev)
495597088cSDongdong Hao {
505597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
515597088cSDongdong Hao
525597088cSDongdong Hao if (!shost)
535597088cSDongdong Hao return NULL;
545597088cSDongdong Hao
555597088cSDongdong Hao return shost_priv(shost);
565597088cSDongdong Hao }
575597088cSDongdong Hao
leapraid_set_tm_flg(struct leapraid_adapter * adapter,u16 hdl)585597088cSDongdong Hao void leapraid_set_tm_flg(struct leapraid_adapter *adapter, u16 hdl)
595597088cSDongdong Hao {
605597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
615597088cSDongdong Hao struct scsi_device *sdev;
625597088cSDongdong Hao bool skip = false;
635597088cSDongdong Hao
645597088cSDongdong Hao /* Iterate over all devices. */
655597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
665597088cSDongdong Hao if (skip)
675597088cSDongdong Hao continue;
685597088cSDongdong Hao
695597088cSDongdong Hao sdev_priv = sdev->hostdata;
705597088cSDongdong Hao if (!sdev_priv)
715597088cSDongdong Hao continue;
725597088cSDongdong Hao
735597088cSDongdong Hao if (sdev_priv->starget_priv->hdl == hdl) {
745597088cSDongdong Hao sdev_priv->starget_priv->tm_busy = 1;
755597088cSDongdong Hao skip = true;
765597088cSDongdong Hao }
775597088cSDongdong Hao }
785597088cSDongdong Hao }
795597088cSDongdong Hao
leapraid_clear_tm_flg(struct leapraid_adapter * adapter,u16 hdl)805597088cSDongdong Hao void leapraid_clear_tm_flg(struct leapraid_adapter *adapter, u16 hdl)
815597088cSDongdong Hao {
825597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
835597088cSDongdong Hao struct scsi_device *sdev;
845597088cSDongdong Hao bool skip = false;
855597088cSDongdong Hao
865597088cSDongdong Hao /* Iterate over all devices. */
875597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
885597088cSDongdong Hao if (skip)
895597088cSDongdong Hao continue;
905597088cSDongdong Hao
915597088cSDongdong Hao sdev_priv = sdev->hostdata;
925597088cSDongdong Hao if (!sdev_priv)
935597088cSDongdong Hao continue;
945597088cSDongdong Hao
955597088cSDongdong Hao if (sdev_priv->starget_priv->hdl == hdl) {
965597088cSDongdong Hao sdev_priv->starget_priv->tm_busy = 0;
975597088cSDongdong Hao skip = true;
985597088cSDongdong Hao }
995597088cSDongdong Hao }
1005597088cSDongdong Hao }
1015597088cSDongdong Hao
leapraid_tm_cmd_map_status(struct leapraid_adapter * adapter,uint channel,uint id,uint lun,u8 type,u16 taskid_task)1025597088cSDongdong Hao static int leapraid_tm_cmd_map_status(struct leapraid_adapter *adapter,
1035597088cSDongdong Hao uint channel,
1045597088cSDongdong Hao uint id,
1055597088cSDongdong Hao uint lun,
1065597088cSDongdong Hao u8 type,
1075597088cSDongdong Hao u16 taskid_task)
1085597088cSDongdong Hao {
1095597088cSDongdong Hao int rc = FAILED;
1105597088cSDongdong Hao
1115597088cSDongdong Hao if (taskid_task <= adapter->shost->can_queue) {
1125597088cSDongdong Hao switch (type) {
1135597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_ABRT_TASK_SET:
1145597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_LOGICAL_UNIT_RESET:
1155597088cSDongdong Hao if (!leapraid_scmd_find_by_lun(adapter, id, lun,
1165597088cSDongdong Hao channel))
1175597088cSDongdong Hao rc = SUCCESS;
1185597088cSDongdong Hao break;
1195597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_TARGET_RESET:
1205597088cSDongdong Hao if (!leapraid_scmd_find_by_tgt(adapter, id, channel))
1215597088cSDongdong Hao rc = SUCCESS;
1225597088cSDongdong Hao break;
1235597088cSDongdong Hao default:
1245597088cSDongdong Hao rc = SUCCESS;
1255597088cSDongdong Hao }
1265597088cSDongdong Hao }
1275597088cSDongdong Hao
1285597088cSDongdong Hao if (taskid_task == adapter->driver_cmds.ctl_cmd.hp_taskid &&
1295597088cSDongdong Hao (adapter->driver_cmds.ctl_cmd.status &
1305597088cSDongdong Hao LEAPRAID_CMD_DONE ||
1315597088cSDongdong Hao adapter->driver_cmds.ctl_cmd.status &
1325597088cSDongdong Hao LEAPRAID_CMD_NOT_USED))
1335597088cSDongdong Hao rc = SUCCESS;
1345597088cSDongdong Hao
1355597088cSDongdong Hao return rc;
1365597088cSDongdong Hao }
1375597088cSDongdong Hao
leapraid_tm_post_processing(struct leapraid_adapter * adapter,u16 hdl,uint channel,uint id,uint lun,u8 type,u16 taskid_task)1385597088cSDongdong Hao static int leapraid_tm_post_processing(struct leapraid_adapter *adapter,
1395597088cSDongdong Hao u16 hdl, uint channel, uint id,
1405597088cSDongdong Hao uint lun, u8 type, u16 taskid_task)
1415597088cSDongdong Hao {
1425597088cSDongdong Hao int rc;
1435597088cSDongdong Hao
1445597088cSDongdong Hao rc = leapraid_tm_cmd_map_status(adapter, channel, id, lun,
1455597088cSDongdong Hao type, taskid_task);
1465597088cSDongdong Hao if (rc == SUCCESS)
1475597088cSDongdong Hao return rc;
1485597088cSDongdong Hao
1495597088cSDongdong Hao leapraid_mask_int(adapter);
1505597088cSDongdong Hao leapraid_sync_irqs(adapter, true);
1515597088cSDongdong Hao leapraid_unmask_int(adapter);
1525597088cSDongdong Hao
1535597088cSDongdong Hao return leapraid_tm_cmd_map_status(adapter, channel, id, lun, type,
1545597088cSDongdong Hao taskid_task);
1555597088cSDongdong Hao }
1565597088cSDongdong Hao
leapraid_build_tm_req(struct leapraid_scsi_tm_req * scsi_tm_req,u16 hdl,uint lun,u8 type,u8 tr_method,u16 target_taskid)1575597088cSDongdong Hao static void leapraid_build_tm_req(struct leapraid_scsi_tm_req *scsi_tm_req,
1585597088cSDongdong Hao u16 hdl, uint lun, u8 type, u8 tr_method,
1595597088cSDongdong Hao u16 target_taskid)
1605597088cSDongdong Hao {
1615597088cSDongdong Hao memset(scsi_tm_req, 0, sizeof(*scsi_tm_req));
1625597088cSDongdong Hao scsi_tm_req->func = LEAPRAID_FUNC_SCSI_TMF;
1635597088cSDongdong Hao scsi_tm_req->dev_hdl = cpu_to_le16(hdl);
1645597088cSDongdong Hao scsi_tm_req->task_type = type;
1655597088cSDongdong Hao scsi_tm_req->msg_flg = tr_method;
1665597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK ||
1675597088cSDongdong Hao type == LEAPRAID_TM_TASKTYPE_QUERY_TASK)
1685597088cSDongdong Hao scsi_tm_req->task_mid = cpu_to_le16(target_taskid);
1695597088cSDongdong Hao int_to_scsilun(lun, (struct scsi_lun *)scsi_tm_req->lun);
1705597088cSDongdong Hao }
1715597088cSDongdong Hao
leapraid_issue_tm(struct leapraid_adapter * adapter,u16 hdl,uint channel,uint id,uint lun,u8 type,u16 target_taskid,u8 tr_method)1725597088cSDongdong Hao int leapraid_issue_tm(struct leapraid_adapter *adapter, u16 hdl, uint channel,
1735597088cSDongdong Hao uint id, uint lun, u8 type,
1745597088cSDongdong Hao u16 target_taskid, u8 tr_method)
1755597088cSDongdong Hao {
1765597088cSDongdong Hao struct leapraid_scsi_tm_req *scsi_tm_req;
1775597088cSDongdong Hao struct leapraid_scsiio_req *scsiio_req;
1785597088cSDongdong Hao struct leapraid_io_req_tracker *io_req_tracker = NULL;
1795597088cSDongdong Hao u16 msix_task;
1805597088cSDongdong Hao u16 taskid;
1815597088cSDongdong Hao bool issue_reset = false;
1825597088cSDongdong Hao u32 db;
1835597088cSDongdong Hao int rc;
1845597088cSDongdong Hao
1855597088cSDongdong Hao lockdep_assert_held(&adapter->driver_cmds.tm_cmd.mutex);
1865597088cSDongdong Hao
1875597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
1885597088cSDongdong Hao adapter->access_ctrl.host_removing ||
1895597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) {
1905597088cSDongdong Hao dev_info(&adapter->pdev->dev,
1915597088cSDongdong Hao "%s %s: Host is recovering, skip tm command!\n",
1925597088cSDongdong Hao __func__, adapter->adapter_attr.name);
1935597088cSDongdong Hao return FAILED;
1945597088cSDongdong Hao }
1955597088cSDongdong Hao
1965597088cSDongdong Hao db = leapraid_readl(&adapter->iomem_base->db);
1975597088cSDongdong Hao if (db & LEAPRAID_DB_USED) {
1985597088cSDongdong Hao dev_info(&adapter->pdev->dev,
1995597088cSDongdong Hao "%s Unexpected db status, issuing hard reset!\n",
2005597088cSDongdong Hao adapter->adapter_attr.name);
2015597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
2025597088cSDongdong Hao __func__, __LINE__);
2035597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
2045597088cSDongdong Hao return !rc ? SUCCESS : FAILED;
2055597088cSDongdong Hao }
2065597088cSDongdong Hao
2075597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) == LEAPRAID_DB_FAULT) {
2085597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
2095597088cSDongdong Hao __func__, __LINE__);
2105597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
2115597088cSDongdong Hao return !rc ? SUCCESS : FAILED;
2125597088cSDongdong Hao }
2135597088cSDongdong Hao
2145597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK)
2155597088cSDongdong Hao io_req_tracker =
2165597088cSDongdong Hao leapraid_get_io_tracker_from_taskid(adapter,
2175597088cSDongdong Hao target_taskid);
2185597088cSDongdong Hao
2195597088cSDongdong Hao adapter->driver_cmds.tm_cmd.status = LEAPRAID_CMD_PENDING;
2205597088cSDongdong Hao scsi_tm_req =
2215597088cSDongdong Hao leapraid_get_task_desc(adapter,
2225597088cSDongdong Hao adapter->driver_cmds.tm_cmd.hp_taskid);
2235597088cSDongdong Hao leapraid_build_tm_req(scsi_tm_req, hdl, lun, type, tr_method,
2245597088cSDongdong Hao target_taskid);
2255597088cSDongdong Hao memset(&adapter->driver_cmds.tm_cmd.reply, 0,
2265597088cSDongdong Hao sizeof(struct leapraid_scsi_tm_rep));
2275597088cSDongdong Hao leapraid_set_tm_flg(adapter, hdl);
2285597088cSDongdong Hao init_completion(&adapter->driver_cmds.tm_cmd.done);
2295597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK &&
2305597088cSDongdong Hao io_req_tracker &&
2315597088cSDongdong Hao io_req_tracker->msix_io < adapter->adapter_attr.rq_cnt)
2325597088cSDongdong Hao msix_task = io_req_tracker->msix_io;
2335597088cSDongdong Hao else
2345597088cSDongdong Hao msix_task = 0;
2355597088cSDongdong Hao taskid = adapter->driver_cmds.tm_cmd.hp_taskid;
2365597088cSDongdong Hao leapraid_fire_hpr_task(adapter, taskid, msix_task);
2375597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.tm_cmd.done,
2385597088cSDongdong Hao LEAPRAID_TM_CMD_TIMEOUT * HZ);
2395597088cSDongdong Hao if (!(adapter->driver_cmds.tm_cmd.status & LEAPRAID_CMD_DONE)) {
2405597088cSDongdong Hao dev_err(&adapter->pdev->dev,
2415597088cSDongdong Hao "%s: TM cmd timeout, status=0x%x\n",
2425597088cSDongdong Hao __func__, adapter->driver_cmds.tm_cmd.status);
2435597088cSDongdong Hao leapraid_log_req_context(adapter, taskid, scsi_tm_req);
2445597088cSDongdong Hao issue_reset =
2455597088cSDongdong Hao leapraid_check_reset(
2465597088cSDongdong Hao adapter->driver_cmds.tm_cmd.status);
2475597088cSDongdong Hao if (issue_reset) {
2485597088cSDongdong Hao dev_info(&adapter->pdev->dev,
2495597088cSDongdong Hao "%s:%d: call hard_reset\n",
2505597088cSDongdong Hao __func__, __LINE__);
2515597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
2525597088cSDongdong Hao rc = !rc ? SUCCESS : FAILED;
2535597088cSDongdong Hao goto out_cleanup;
2545597088cSDongdong Hao }
2555597088cSDongdong Hao }
2565597088cSDongdong Hao
2575597088cSDongdong Hao leapraid_sync_irqs(adapter, false);
2585597088cSDongdong Hao
2595597088cSDongdong Hao switch (type) {
2605597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_TARGET_RESET:
2615597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_ABRT_TASK_SET:
2625597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_LOGICAL_UNIT_RESET:
2635597088cSDongdong Hao rc = leapraid_tm_post_processing(adapter, hdl, channel, id,
2645597088cSDongdong Hao lun, type, target_taskid);
2655597088cSDongdong Hao break;
2665597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_ABORT_TASK:
2675597088cSDongdong Hao rc = SUCCESS;
2685597088cSDongdong Hao scsiio_req = leapraid_get_task_desc(adapter, target_taskid);
2695597088cSDongdong Hao if (le16_to_cpu(scsiio_req->dev_hdl) != hdl)
2705597088cSDongdong Hao break;
2715597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: Abort failed, hdl=0x%04x\n",
2725597088cSDongdong Hao adapter->adapter_attr.name, hdl);
2735597088cSDongdong Hao rc = FAILED;
2745597088cSDongdong Hao break;
2755597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_QUERY_TASK:
2765597088cSDongdong Hao rc = SUCCESS;
2775597088cSDongdong Hao break;
2785597088cSDongdong Hao default:
2795597088cSDongdong Hao rc = FAILED;
2805597088cSDongdong Hao break;
2815597088cSDongdong Hao }
2825597088cSDongdong Hao
2835597088cSDongdong Hao out_cleanup:
2845597088cSDongdong Hao leapraid_clear_tm_flg(adapter, hdl);
2855597088cSDongdong Hao adapter->driver_cmds.tm_cmd.status = LEAPRAID_CMD_NOT_USED;
2865597088cSDongdong Hao return rc;
2875597088cSDongdong Hao }
2885597088cSDongdong Hao
leapraid_issue_locked_tm(struct leapraid_adapter * adapter,u16 hdl,uint channel,uint id,uint lun,u8 type,u16 target_taskid,u8 tr_method)2895597088cSDongdong Hao int leapraid_issue_locked_tm(struct leapraid_adapter *adapter, u16 hdl,
2905597088cSDongdong Hao uint channel, uint id, uint lun, u8 type,
2915597088cSDongdong Hao u16 target_taskid, u8 tr_method)
2925597088cSDongdong Hao {
2935597088cSDongdong Hao int rc;
2945597088cSDongdong Hao
2955597088cSDongdong Hao mutex_lock(&adapter->driver_cmds.tm_cmd.mutex);
2965597088cSDongdong Hao rc = leapraid_issue_tm(adapter, hdl, channel, id, lun, type,
2975597088cSDongdong Hao target_taskid, tr_method);
2985597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.tm_cmd.mutex);
2995597088cSDongdong Hao
3005597088cSDongdong Hao return rc;
3015597088cSDongdong Hao }
3025597088cSDongdong Hao
leapraid_smart_fault_detect(struct leapraid_adapter * adapter,u16 hdl)3035597088cSDongdong Hao void leapraid_smart_fault_detect(struct leapraid_adapter *adapter, u16 hdl)
3045597088cSDongdong Hao {
3055597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
3065597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
3075597088cSDongdong Hao struct scsi_target *starget;
3085597088cSDongdong Hao unsigned long flags;
3095597088cSDongdong Hao
3105597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
3115597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
3125597088cSDongdong Hao if (!sas_dev) {
3135597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
3145597088cSDongdong Hao return;
3155597088cSDongdong Hao }
3165597088cSDongdong Hao
3175597088cSDongdong Hao starget = sas_dev->starget;
3185597088cSDongdong Hao starget_priv = starget ? starget->hostdata : NULL;
3195597088cSDongdong Hao if (!starget_priv) {
3205597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
3215597088cSDongdong Hao goto release_sdev;
3225597088cSDongdong Hao }
3235597088cSDongdong Hao
3245597088cSDongdong Hao if (starget_priv->flg & LEAPRAID_TGT_FLG_RAID_MEMBER ||
3255597088cSDongdong Hao starget_priv->flg & LEAPRAID_TGT_FLG_VOLUME) {
3265597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
3275597088cSDongdong Hao goto release_sdev;
3285597088cSDongdong Hao }
3295597088cSDongdong Hao
3305597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
3315597088cSDongdong Hao leapraid_async_turn_on_led(adapter, hdl);
3325597088cSDongdong Hao release_sdev:
3335597088cSDongdong Hao if (sas_dev)
3345597088cSDongdong Hao leapraid_sdev_put(sas_dev);
3355597088cSDongdong Hao }
3365597088cSDongdong Hao
leapraid_process_sense_data(struct leapraid_adapter * adapter,struct leapraid_scsiio_rep * scsiio_rep,struct scsi_cmnd * scmd,u16 taskid)3375597088cSDongdong Hao static void leapraid_process_sense_data(struct leapraid_adapter *adapter,
3385597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_rep,
3395597088cSDongdong Hao struct scsi_cmnd *scmd, u16 taskid)
3405597088cSDongdong Hao {
3415597088cSDongdong Hao struct sense_info data;
3425597088cSDongdong Hao const void *sense_data;
3435597088cSDongdong Hao u32 sz;
3445597088cSDongdong Hao
3455597088cSDongdong Hao if (!(scsiio_rep->scsi_state & LEAPRAID_SCSI_STATE_AUTOSENSE_VALID))
3465597088cSDongdong Hao return;
3475597088cSDongdong Hao
3485597088cSDongdong Hao sense_data = leapraid_get_sense_buffer(adapter, taskid);
3495597088cSDongdong Hao sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
3505597088cSDongdong Hao le32_to_cpu(scsiio_rep->sense_count));
3515597088cSDongdong Hao
3525597088cSDongdong Hao memcpy(scmd->sense_buffer, sense_data, sz);
3535597088cSDongdong Hao leapraid_get_sense_data(scmd->sense_buffer, &data);
3545597088cSDongdong Hao if (data.asc == ASC_FAILURE_PREDICTION_THRESHOLD_EXCEEDED)
3555597088cSDongdong Hao leapraid_smart_fault_detect(adapter,
3565597088cSDongdong Hao le16_to_cpu(scsiio_rep->dev_hdl));
3575597088cSDongdong Hao }
3585597088cSDongdong Hao
leapraid_handle_data_underrun(struct leapraid_scsiio_rep * scsiio_rep,struct scsi_cmnd * scmd,u32 xfer_cnt)3595597088cSDongdong Hao static void leapraid_handle_data_underrun(
3605597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_rep,
3615597088cSDongdong Hao struct scsi_cmnd *scmd, u32 xfer_cnt)
3625597088cSDongdong Hao {
3635597088cSDongdong Hao u8 scsi_status = scsiio_rep->scsi_status;
3645597088cSDongdong Hao u8 scsi_state = scsiio_rep->scsi_state;
3655597088cSDongdong Hao
3665597088cSDongdong Hao scmd->result = (DID_OK << LEAPRAID_SCSI_HOST_SHIFT) | scsi_status;
3675597088cSDongdong Hao
3685597088cSDongdong Hao if (scsi_state & LEAPRAID_SCSI_STATE_AUTOSENSE_VALID)
3695597088cSDongdong Hao return;
3705597088cSDongdong Hao
3715597088cSDongdong Hao if (xfer_cnt < scmd->underflow) {
3725597088cSDongdong Hao if (scsi_status == SAM_STAT_BUSY)
3735597088cSDongdong Hao scmd->result = SAM_STAT_BUSY;
3745597088cSDongdong Hao else
3755597088cSDongdong Hao scmd->result = DID_SOFT_ERROR <<
3765597088cSDongdong Hao LEAPRAID_SCSI_HOST_SHIFT;
3775597088cSDongdong Hao } else if (scsi_state & (LEAPRAID_SCSI_STATE_AUTOSENSE_FAILED |
3785597088cSDongdong Hao LEAPRAID_SCSI_STATE_NO_SCSI_STATUS)) {
3795597088cSDongdong Hao scmd->result = DID_SOFT_ERROR << LEAPRAID_SCSI_HOST_SHIFT;
3805597088cSDongdong Hao } else if (scsi_state & LEAPRAID_SCSI_STATE_TERMINATED) {
3815597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
3825597088cSDongdong Hao } else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3835597088cSDongdong Hao scsiio_rep->scsi_state = LEAPRAID_SCSI_STATE_AUTOSENSE_VALID;
3845597088cSDongdong Hao scsiio_rep->scsi_status = SAM_STAT_CHECK_CONDITION;
3855597088cSDongdong Hao scsi_build_sense(scmd, 0, ILLEGAL_REQUEST,
3865597088cSDongdong Hao LEAPRAID_SCSI_ASC_INVALID_CMD_CODE,
3875597088cSDongdong Hao LEAPRAID_SCSI_ASCQ_DEFAULT);
3885597088cSDongdong Hao }
3895597088cSDongdong Hao }
3905597088cSDongdong Hao
leapraid_handle_success_status(struct leapraid_scsiio_rep * scsiio_rep,struct scsi_cmnd * scmd,u32 response_code)3915597088cSDongdong Hao static void leapraid_handle_success_status(
3925597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_rep,
3935597088cSDongdong Hao struct scsi_cmnd *scmd,
3945597088cSDongdong Hao u32 response_code)
3955597088cSDongdong Hao {
3965597088cSDongdong Hao u8 scsi_status = scsiio_rep->scsi_status;
3975597088cSDongdong Hao u8 scsi_state = scsiio_rep->scsi_state;
3985597088cSDongdong Hao
3995597088cSDongdong Hao scmd->result = (DID_OK << LEAPRAID_SCSI_HOST_SHIFT) | scsi_status;
4005597088cSDongdong Hao
4015597088cSDongdong Hao if (response_code == LEAPRAID_TM_RSP_INVALID_FRAME ||
4025597088cSDongdong Hao (scsi_state & (LEAPRAID_SCSI_STATE_AUTOSENSE_FAILED |
4035597088cSDongdong Hao LEAPRAID_SCSI_STATE_NO_SCSI_STATUS)))
4045597088cSDongdong Hao scmd->result = DID_SOFT_ERROR << LEAPRAID_SCSI_HOST_SHIFT;
4055597088cSDongdong Hao else if (scsi_state & LEAPRAID_SCSI_STATE_TERMINATED)
4065597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
4075597088cSDongdong Hao }
4085597088cSDongdong Hao
leapraid_scsiio_done_dispatch(struct leapraid_adapter * adapter,struct leapraid_scsiio_rep * scsiio_rep,struct leapraid_sdev_priv * sdev_priv,struct scsi_cmnd * scmd,u16 taskid,u32 response_code)4095597088cSDongdong Hao static void leapraid_scsiio_done_dispatch(
4105597088cSDongdong Hao struct leapraid_adapter *adapter,
4115597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_rep,
4125597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv,
4135597088cSDongdong Hao struct scsi_cmnd *scmd,
4145597088cSDongdong Hao u16 taskid, u32 response_code)
4155597088cSDongdong Hao {
4165597088cSDongdong Hao u8 scsi_status = scsiio_rep->scsi_status;
4175597088cSDongdong Hao u8 scsi_state = scsiio_rep->scsi_state;
4185597088cSDongdong Hao u16 adapter_status;
4195597088cSDongdong Hao u32 xfer_cnt;
4205597088cSDongdong Hao u32 sz;
4215597088cSDongdong Hao
4225597088cSDongdong Hao adapter_status = le16_to_cpu(scsiio_rep->adapter_status) &
4235597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
4245597088cSDongdong Hao
4255597088cSDongdong Hao xfer_cnt = le32_to_cpu(scsiio_rep->transfer_count);
4265597088cSDongdong Hao scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
4275597088cSDongdong Hao
4285597088cSDongdong Hao if (adapter_status == LEAPRAID_ADAPTER_STATUS_SCSI_DATA_UNDERRUN &&
4295597088cSDongdong Hao xfer_cnt == 0 &&
4305597088cSDongdong Hao (scsi_status == LEAPRAID_SCSI_STATUS_BUSY ||
4315597088cSDongdong Hao scsi_status == LEAPRAID_SCSI_STATUS_RESERVATION_CONFLICT ||
4325597088cSDongdong Hao scsi_status == LEAPRAID_SCSI_STATUS_TASK_SET_FULL))
4335597088cSDongdong Hao adapter_status = LEAPRAID_ADAPTER_STATUS_SUCCESS;
4345597088cSDongdong Hao
4355597088cSDongdong Hao switch (adapter_status) {
4365597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_DEVICE_NOT_THERE:
4375597088cSDongdong Hao scmd->result = DID_NO_CONNECT << LEAPRAID_SCSI_HOST_SHIFT;
4385597088cSDongdong Hao break;
4395597088cSDongdong Hao
4405597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_BUSY:
4415597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_INSUFFICIENT_RESOURCES:
4425597088cSDongdong Hao scmd->result = SAM_STAT_BUSY;
4435597088cSDongdong Hao break;
4445597088cSDongdong Hao
4455597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_RESIDUAL_MISMATCH:
4465597088cSDongdong Hao if (xfer_cnt == 0 || scmd->underflow > xfer_cnt)
4475597088cSDongdong Hao scmd->result = DID_SOFT_ERROR <<
4485597088cSDongdong Hao LEAPRAID_SCSI_HOST_SHIFT;
4495597088cSDongdong Hao else
4505597088cSDongdong Hao scmd->result = (DID_OK << LEAPRAID_SCSI_HOST_SHIFT) |
4515597088cSDongdong Hao scsi_status;
4525597088cSDongdong Hao break;
4535597088cSDongdong Hao
4545597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_ADAPTER_TERMINATED:
4555597088cSDongdong Hao if (sdev_priv->block) {
4565597088cSDongdong Hao scmd->result = DID_TRANSPORT_DISRUPTED <<
4575597088cSDongdong Hao LEAPRAID_SCSI_HOST_SHIFT;
4585597088cSDongdong Hao return;
4595597088cSDongdong Hao }
4605597088cSDongdong Hao
4615597088cSDongdong Hao if (scmd->device->channel == RAID_CHANNEL &&
4625597088cSDongdong Hao scsi_state == (LEAPRAID_SCSI_STATE_TERMINATED |
4635597088cSDongdong Hao LEAPRAID_SCSI_STATE_NO_SCSI_STATUS)) {
4645597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
4655597088cSDongdong Hao break;
4665597088cSDongdong Hao }
4675597088cSDongdong Hao
4685597088cSDongdong Hao scmd->result = DID_SOFT_ERROR << LEAPRAID_SCSI_HOST_SHIFT;
4695597088cSDongdong Hao break;
4705597088cSDongdong Hao
4715597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_TASK_TERMINATED:
4725597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_EXT_TERMINATED:
4735597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
4745597088cSDongdong Hao break;
4755597088cSDongdong Hao
4765597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_DATA_UNDERRUN:
4775597088cSDongdong Hao leapraid_handle_data_underrun(scsiio_rep, scmd, xfer_cnt);
4785597088cSDongdong Hao break;
4795597088cSDongdong Hao
4805597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_DATA_OVERRUN:
4815597088cSDongdong Hao scsi_set_resid(scmd, 0);
4825597088cSDongdong Hao leapraid_handle_success_status(scsiio_rep, scmd,
4835597088cSDongdong Hao response_code);
4845597088cSDongdong Hao break;
4855597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_RECOVERED_ERROR:
4865597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SUCCESS:
4875597088cSDongdong Hao leapraid_handle_success_status(scsiio_rep, scmd,
4885597088cSDongdong Hao response_code);
4895597088cSDongdong Hao break;
4905597088cSDongdong Hao
4915597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_PROTOCOL_ERROR:
4925597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_INTERNAL_ERROR:
4935597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_IO_DATA_ERROR:
4945597088cSDongdong Hao case LEAPRAID_ADAPTER_STATUS_SCSI_TASK_MGMT_FAILED:
4955597088cSDongdong Hao default:
4965597088cSDongdong Hao scmd->result = DID_SOFT_ERROR << LEAPRAID_SCSI_HOST_SHIFT;
4975597088cSDongdong Hao break;
4985597088cSDongdong Hao }
4995597088cSDongdong Hao
5005597088cSDongdong Hao if (!scmd->result)
5015597088cSDongdong Hao return;
5025597088cSDongdong Hao
5035597088cSDongdong Hao scsi_print_command(scmd);
5045597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
5055597088cSDongdong Hao "SCSI I/O: hdl=0x%x, status: 0x%x, 0x%x, 0x%x\n",
5065597088cSDongdong Hao le16_to_cpu(scsiio_rep->dev_hdl), adapter_status,
5075597088cSDongdong Hao scsi_status, scsi_state);
5085597088cSDongdong Hao
5095597088cSDongdong Hao if (scsi_state & LEAPRAID_SCSI_STATE_AUTOSENSE_VALID) {
5105597088cSDongdong Hao struct scsi_sense_hdr sshdr;
5115597088cSDongdong Hao
5125597088cSDongdong Hao sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
5135597088cSDongdong Hao le32_to_cpu(scsiio_rep->sense_count));
5145597088cSDongdong Hao if (scsi_normalize_sense(scmd->sense_buffer, sz,
5155597088cSDongdong Hao &sshdr))
5165597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
5175597088cSDongdong Hao "Sense: key=0x%x asc=0x%x ascq=0x%x\n",
5185597088cSDongdong Hao sshdr.sense_key, sshdr.asc,
5195597088cSDongdong Hao sshdr.ascq);
5205597088cSDongdong Hao else
5215597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
5225597088cSDongdong Hao "Sense: Invalid sense data\n");
5235597088cSDongdong Hao }
5245597088cSDongdong Hao }
5255597088cSDongdong Hao
leapraid_scsiio_done(struct leapraid_adapter * adapter,u16 taskid,u8 msix_index,u32 rep)5265597088cSDongdong Hao bool leapraid_scsiio_done(struct leapraid_adapter *adapter, u16 taskid,
5275597088cSDongdong Hao u8 msix_index, u32 rep)
5285597088cSDongdong Hao {
5295597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_rep;
5305597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
5315597088cSDongdong Hao struct scsi_cmnd *scmd;
5325597088cSDongdong Hao u32 response_code = 0;
5335597088cSDongdong Hao
5345597088cSDongdong Hao scmd = leapraid_get_scmd_from_taskid(adapter, taskid);
5355597088cSDongdong Hao if (!scmd)
5365597088cSDongdong Hao return true;
5375597088cSDongdong Hao
5385597088cSDongdong Hao scsiio_rep = leapraid_get_reply_vaddr(adapter, rep);
5395597088cSDongdong Hao if (!scsiio_rep) {
5405597088cSDongdong Hao scmd->result = DID_OK << LEAPRAID_SCSI_HOST_SHIFT;
5415597088cSDongdong Hao goto out_scsiio_done;
5425597088cSDongdong Hao }
5435597088cSDongdong Hao
5445597088cSDongdong Hao sdev_priv = scmd->device->hostdata;
5455597088cSDongdong Hao if (!sdev_priv ||
5465597088cSDongdong Hao !sdev_priv->starget_priv ||
5475597088cSDongdong Hao sdev_priv->starget_priv->deleted) {
5485597088cSDongdong Hao scmd->result = DID_NO_CONNECT << LEAPRAID_SCSI_HOST_SHIFT;
5495597088cSDongdong Hao goto out_scsiio_done;
5505597088cSDongdong Hao }
5515597088cSDongdong Hao
5525597088cSDongdong Hao if (scsiio_rep->scsi_state & LEAPRAID_SCSI_STATE_RESPONSE_INFO_VALID)
5535597088cSDongdong Hao response_code = le32_to_cpu(scsiio_rep->resp_info) & 0xFF;
5545597088cSDongdong Hao
5555597088cSDongdong Hao leapraid_process_sense_data(adapter, scsiio_rep, scmd, taskid);
5565597088cSDongdong Hao leapraid_scsiio_done_dispatch(adapter, scsiio_rep, sdev_priv, scmd,
5575597088cSDongdong Hao taskid, response_code);
5585597088cSDongdong Hao
5595597088cSDongdong Hao out_scsiio_done:
5605597088cSDongdong Hao scsi_dma_unmap(scmd);
5615597088cSDongdong Hao leapraid_free_taskid(adapter, taskid);
5625597088cSDongdong Hao scsi_done(scmd);
5635597088cSDongdong Hao return false;
5645597088cSDongdong Hao }
5655597088cSDongdong Hao
leapraid_probe_raid(struct leapraid_adapter * adapter)5665597088cSDongdong Hao static void leapraid_probe_raid(struct leapraid_adapter *adapter)
5675597088cSDongdong Hao {
5685597088cSDongdong Hao struct leapraid_raid_volume *raid_volume, *next_raid_volume;
5695597088cSDongdong Hao unsigned long flags;
5705597088cSDongdong Hao LIST_HEAD(head);
5715597088cSDongdong Hao int rc;
5725597088cSDongdong Hao
5735597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
5745597088cSDongdong Hao list_splice_init(&adapter->dev_topo.raid_volume_list, &head);
5755597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
5765597088cSDongdong Hao
5775597088cSDongdong Hao list_for_each_entry_safe(raid_volume, next_raid_volume, &head, list) {
5785597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
5795597088cSDongdong Hao list_move_tail(&raid_volume->list,
5805597088cSDongdong Hao &adapter->dev_topo.raid_volume_list);
5815597088cSDongdong Hao if (raid_volume->starget) {
5825597088cSDongdong Hao spin_unlock_irqrestore(
5835597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
5845597088cSDongdong Hao continue;
5855597088cSDongdong Hao }
5865597088cSDongdong Hao
5875597088cSDongdong Hao leapraid_raid_volume_get(raid_volume);
5885597088cSDongdong Hao spin_unlock_irqrestore(
5895597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
5905597088cSDongdong Hao
5915597088cSDongdong Hao rc = scsi_add_device(adapter->shost, RAID_CHANNEL,
5925597088cSDongdong Hao raid_volume->id, 0);
5935597088cSDongdong Hao if (rc)
5945597088cSDongdong Hao leapraid_raid_volume_remove(adapter, raid_volume);
5955597088cSDongdong Hao
5965597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
5975597088cSDongdong Hao }
5985597088cSDongdong Hao }
5995597088cSDongdong Hao
leapraid_sas_dev_make_active(struct leapraid_adapter * adapter,struct leapraid_sas_dev * sas_dev)6005597088cSDongdong Hao static void leapraid_sas_dev_make_active(struct leapraid_adapter *adapter,
6015597088cSDongdong Hao struct leapraid_sas_dev *sas_dev)
6025597088cSDongdong Hao {
6035597088cSDongdong Hao unsigned long flags;
6045597088cSDongdong Hao
6055597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
6065597088cSDongdong Hao if (!list_empty(&sas_dev->list)) {
6075597088cSDongdong Hao list_del_init(&sas_dev->list);
6085597088cSDongdong Hao leapraid_sdev_put(sas_dev);
6095597088cSDongdong Hao }
6105597088cSDongdong Hao
6115597088cSDongdong Hao leapraid_sdev_get(sas_dev);
6125597088cSDongdong Hao list_add_tail(&sas_dev->list, &adapter->dev_topo.sas_dev_list);
6135597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
6145597088cSDongdong Hao }
6155597088cSDongdong Hao
leapraid_probe_sas(struct leapraid_adapter * adapter)6165597088cSDongdong Hao static void leapraid_probe_sas(struct leapraid_adapter *adapter)
6175597088cSDongdong Hao {
6185597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
6195597088cSDongdong Hao bool added;
6205597088cSDongdong Hao
6215597088cSDongdong Hao for (;;) {
6225597088cSDongdong Hao sas_dev = leapraid_get_next_sas_dev_from_init_list(adapter);
6235597088cSDongdong Hao if (!sas_dev)
6245597088cSDongdong Hao break;
6255597088cSDongdong Hao added = leapraid_transport_port_add(adapter,
6265597088cSDongdong Hao sas_dev->hdl,
6275597088cSDongdong Hao sas_dev->parent_sas_addr,
6285597088cSDongdong Hao sas_dev->card_port);
6295597088cSDongdong Hao if (!added)
6305597088cSDongdong Hao goto remove_dev;
6315597088cSDongdong Hao
6325597088cSDongdong Hao if (!sas_dev->starget &&
6335597088cSDongdong Hao !adapter->scan_dev_desc.driver_loading) {
6345597088cSDongdong Hao leapraid_transport_port_remove(adapter,
6355597088cSDongdong Hao sas_dev->sas_addr,
6365597088cSDongdong Hao sas_dev->parent_sas_addr,
6375597088cSDongdong Hao sas_dev->card_port);
6385597088cSDongdong Hao goto remove_dev;
6395597088cSDongdong Hao }
6405597088cSDongdong Hao
6415597088cSDongdong Hao leapraid_sas_dev_make_active(adapter, sas_dev);
6425597088cSDongdong Hao leapraid_sdev_put(sas_dev);
6435597088cSDongdong Hao continue;
6445597088cSDongdong Hao
6455597088cSDongdong Hao remove_dev:
6465597088cSDongdong Hao leapraid_sas_dev_remove(adapter, sas_dev);
6475597088cSDongdong Hao leapraid_sdev_put(sas_dev);
6485597088cSDongdong Hao }
6495597088cSDongdong Hao }
6505597088cSDongdong Hao
leapraid_get_boot_dev(struct leapraid_adapter * adapter,struct leapraid_boot_dev * boot_dev,void ** pdev,u32 * pchnl)6515597088cSDongdong Hao static bool leapraid_get_boot_dev(struct leapraid_adapter *adapter,
6525597088cSDongdong Hao struct leapraid_boot_dev *boot_dev,
6535597088cSDongdong Hao void **pdev, u32 *pchnl)
6545597088cSDongdong Hao {
6555597088cSDongdong Hao unsigned long flags;
6565597088cSDongdong Hao void *dev;
6575597088cSDongdong Hao u32 chnl;
6585597088cSDongdong Hao
6595597088cSDongdong Hao spin_lock_irqsave(&adapter->boot_devs.lock, flags);
6605597088cSDongdong Hao if (!boot_dev->dev) {
6615597088cSDongdong Hao spin_unlock_irqrestore(&adapter->boot_devs.lock, flags);
6625597088cSDongdong Hao return false;
6635597088cSDongdong Hao }
6645597088cSDongdong Hao
6655597088cSDongdong Hao dev = boot_dev->dev;
6665597088cSDongdong Hao chnl = boot_dev->chnl;
6675597088cSDongdong Hao leapraid_boot_dev_get(dev, chnl);
6685597088cSDongdong Hao spin_unlock_irqrestore(&adapter->boot_devs.lock, flags);
6695597088cSDongdong Hao
6705597088cSDongdong Hao *pdev = dev;
6715597088cSDongdong Hao *pchnl = chnl;
6725597088cSDongdong Hao return true;
6735597088cSDongdong Hao }
6745597088cSDongdong Hao
leapraid_probe_boot_dev(struct leapraid_adapter * adapter)6755597088cSDongdong Hao static void leapraid_probe_boot_dev(struct leapraid_adapter *adapter)
6765597088cSDongdong Hao {
6775597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
6785597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
6795597088cSDongdong Hao struct leapraid_sas_port *sport;
6805597088cSDongdong Hao unsigned long flags;
6815597088cSDongdong Hao void *dev = NULL;
6825597088cSDongdong Hao u32 chnl;
6835597088cSDongdong Hao
6845597088cSDongdong Hao if (leapraid_get_boot_dev(adapter,
6855597088cSDongdong Hao &adapter->boot_devs.requested_boot_dev,
6865597088cSDongdong Hao &dev, &chnl))
6875597088cSDongdong Hao goto boot_dev_found;
6885597088cSDongdong Hao
6895597088cSDongdong Hao if (leapraid_get_boot_dev(adapter,
6905597088cSDongdong Hao &adapter->boot_devs.requested_alt_boot_dev,
6915597088cSDongdong Hao &dev, &chnl))
6925597088cSDongdong Hao goto boot_dev_found;
6935597088cSDongdong Hao
6945597088cSDongdong Hao if (leapraid_get_boot_dev(adapter,
6955597088cSDongdong Hao &adapter->boot_devs.current_boot_dev,
6965597088cSDongdong Hao &dev, &chnl))
6975597088cSDongdong Hao goto boot_dev_found;
6985597088cSDongdong Hao
6995597088cSDongdong Hao return;
7005597088cSDongdong Hao
7015597088cSDongdong Hao boot_dev_found:
7025597088cSDongdong Hao switch (chnl) {
7035597088cSDongdong Hao case RAID_CHANNEL:
7045597088cSDongdong Hao raid_volume = dev;
7055597088cSDongdong Hao
7065597088cSDongdong Hao if (raid_volume->starget)
7075597088cSDongdong Hao break;
7085597088cSDongdong Hao
7095597088cSDongdong Hao /* TODO eedp */
7105597088cSDongdong Hao
7115597088cSDongdong Hao if (scsi_add_device(adapter->shost, RAID_CHANNEL,
7125597088cSDongdong Hao raid_volume->id, 0))
7135597088cSDongdong Hao leapraid_raid_volume_remove(adapter, raid_volume);
7145597088cSDongdong Hao break;
7155597088cSDongdong Hao default:
7165597088cSDongdong Hao sas_dev = dev;
7175597088cSDongdong Hao
7185597088cSDongdong Hao if (sas_dev->starget)
7195597088cSDongdong Hao break;
7205597088cSDongdong Hao
7215597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
7225597088cSDongdong Hao list_move_tail(&sas_dev->list,
7235597088cSDongdong Hao &adapter->dev_topo.sas_dev_list);
7245597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
7255597088cSDongdong Hao
7265597088cSDongdong Hao if (!sas_dev->card_port)
7275597088cSDongdong Hao break;
7285597088cSDongdong Hao
7295597088cSDongdong Hao sport = leapraid_transport_port_add(adapter, sas_dev->hdl,
7305597088cSDongdong Hao sas_dev->parent_sas_addr,
7315597088cSDongdong Hao sas_dev->card_port);
7325597088cSDongdong Hao if (!sport)
7335597088cSDongdong Hao leapraid_sas_dev_remove(adapter, sas_dev);
7345597088cSDongdong Hao break;
7355597088cSDongdong Hao }
7365597088cSDongdong Hao
7375597088cSDongdong Hao leapraid_boot_dev_put(dev, chnl);
7385597088cSDongdong Hao }
7395597088cSDongdong Hao
leapraid_probe_devices(struct leapraid_adapter * adapter)7405597088cSDongdong Hao static void leapraid_probe_devices(struct leapraid_adapter *adapter)
7415597088cSDongdong Hao {
7425597088cSDongdong Hao leapraid_probe_boot_dev(adapter);
7435597088cSDongdong Hao
7445597088cSDongdong Hao if (adapter->adapter_attr.raid_support) {
7455597088cSDongdong Hao leapraid_probe_raid(adapter);
7465597088cSDongdong Hao leapraid_probe_sas(adapter);
7475597088cSDongdong Hao } else {
7485597088cSDongdong Hao leapraid_probe_sas(adapter);
7495597088cSDongdong Hao }
7505597088cSDongdong Hao }
7515597088cSDongdong Hao
leapraid_scan_dev_done(struct leapraid_adapter * adapter)7525597088cSDongdong Hao void leapraid_scan_dev_done(struct leapraid_adapter *adapter)
7535597088cSDongdong Hao {
7545597088cSDongdong Hao if (adapter->scan_dev_desc.wait_scan_dev_done) {
7555597088cSDongdong Hao adapter->scan_dev_desc.wait_scan_dev_done = 0;
7565597088cSDongdong Hao leapraid_probe_devices(adapter);
7575597088cSDongdong Hao }
7585597088cSDongdong Hao
7595597088cSDongdong Hao adapter->scan_dev_desc.scan_start = 0;
7605597088cSDongdong Hao
7615597088cSDongdong Hao leapraid_check_scheduled_fault_start(adapter);
7625597088cSDongdong Hao leapraid_fw_log_start(adapter);
7635597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
7645597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
7655597088cSDongdong Hao }
7665597088cSDongdong Hao
7675597088cSDongdong Hao static const struct pci_device_id leapraid_pci_table[] = {
7685597088cSDongdong Hao { PCI_DEVICE_SUB(LEAPRAID_VENDOR_ID, LEAPRAID_DEVID_HBA,
7695597088cSDongdong Hao LEAPRAID_SUBVENDOR_ID,
7705597088cSDongdong Hao LEAPRAID_SUBDEVID_HBA) },
7715597088cSDongdong Hao { 0, }
7725597088cSDongdong Hao };
7735597088cSDongdong Hao
leapraid_is_scmd_permitted(struct leapraid_adapter * adapter,struct scsi_cmnd * scmd)7745597088cSDongdong Hao static inline bool leapraid_is_scmd_permitted(struct leapraid_adapter *adapter,
7755597088cSDongdong Hao struct scsi_cmnd *scmd)
7765597088cSDongdong Hao {
7775597088cSDongdong Hao u8 opcode;
7785597088cSDongdong Hao
7795597088cSDongdong Hao if (adapter->access_ctrl.pcie_recovering ||
7805597088cSDongdong Hao atomic_read(&adapter->overheat_desc.thermal_alert))
7815597088cSDongdong Hao return false;
7825597088cSDongdong Hao
7835597088cSDongdong Hao if (adapter->access_ctrl.host_removing) {
7845597088cSDongdong Hao if (leapraid_pci_removed(adapter))
7855597088cSDongdong Hao return false;
7865597088cSDongdong Hao
7875597088cSDongdong Hao opcode = scmd->cmnd[0];
7885597088cSDongdong Hao return opcode == SYNCHRONIZE_CACHE || opcode == START_STOP;
7895597088cSDongdong Hao }
7905597088cSDongdong Hao return true;
7915597088cSDongdong Hao }
7925597088cSDongdong Hao
leapraid_should_queuecommand(struct leapraid_adapter * adapter,struct leapraid_sdev_priv * sdev_priv,struct scsi_cmnd * scmd,enum scsi_qc_status * rc)7935597088cSDongdong Hao static bool leapraid_should_queuecommand(struct leapraid_adapter *adapter,
7945597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv,
7955597088cSDongdong Hao struct scsi_cmnd *scmd,
7965597088cSDongdong Hao enum scsi_qc_status *rc)
7975597088cSDongdong Hao {
7985597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
7995597088cSDongdong Hao
8005597088cSDongdong Hao if (!sdev_priv || !sdev_priv->starget_priv)
8015597088cSDongdong Hao goto no_connect;
8025597088cSDongdong Hao
8035597088cSDongdong Hao if (!leapraid_is_scmd_permitted(adapter, scmd))
8045597088cSDongdong Hao goto no_connect;
8055597088cSDongdong Hao
8065597088cSDongdong Hao starget_priv = sdev_priv->starget_priv;
8075597088cSDongdong Hao if (starget_priv->hdl == LEAPRAID_INVALID_DEV_HANDLE)
8085597088cSDongdong Hao goto no_connect;
8095597088cSDongdong Hao
8105597088cSDongdong Hao if (sdev_priv->block &&
8114c461ee2SBart Van Assche scsi_get_host_state(scmd->device->host) == SHOST_RECOVERY &&
8125597088cSDongdong Hao scmd->cmnd[0] == TEST_UNIT_READY) {
8135597088cSDongdong Hao scsi_build_sense(scmd, 0, UNIT_ATTENTION,
8145597088cSDongdong Hao LEAPRAID_SCSI_ASC_POWER_ON_RESET,
8155597088cSDongdong Hao LEAPRAID_SCSI_ASCQ_POWER_ON_RESET);
8165597088cSDongdong Hao goto scsiio_done;
8175597088cSDongdong Hao }
8185597088cSDongdong Hao
8195597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
8205597088cSDongdong Hao adapter->reset_desc.adapter_link_resetting) {
8215597088cSDongdong Hao *rc = SCSI_MLQUEUE_HOST_BUSY;
8225597088cSDongdong Hao return false;
8235597088cSDongdong Hao }
8245597088cSDongdong Hao
8255597088cSDongdong Hao if (starget_priv->deleted || sdev_priv->deleted)
8265597088cSDongdong Hao goto no_connect;
8275597088cSDongdong Hao
8285597088cSDongdong Hao if (starget_priv->tm_busy || sdev_priv->block) {
8295597088cSDongdong Hao *rc = SCSI_MLQUEUE_DEVICE_BUSY;
8305597088cSDongdong Hao return false;
8315597088cSDongdong Hao }
8325597088cSDongdong Hao
8335597088cSDongdong Hao return true;
8345597088cSDongdong Hao
8355597088cSDongdong Hao no_connect:
8365597088cSDongdong Hao scmd->result = DID_NO_CONNECT << LEAPRAID_SCSI_HOST_SHIFT;
8375597088cSDongdong Hao scsiio_done:
8385597088cSDongdong Hao scsi_done(scmd);
8395597088cSDongdong Hao
8405597088cSDongdong Hao return false;
8415597088cSDongdong Hao }
8425597088cSDongdong Hao
build_scsiio_req_control(struct scsi_cmnd * scmd,struct leapraid_sdev_priv * sdev_priv)8435597088cSDongdong Hao static u32 build_scsiio_req_control(struct scsi_cmnd *scmd,
8445597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv)
8455597088cSDongdong Hao {
8465597088cSDongdong Hao u32 control;
8475597088cSDongdong Hao
8485597088cSDongdong Hao switch (scmd->sc_data_direction) {
8495597088cSDongdong Hao case DMA_FROM_DEVICE:
8505597088cSDongdong Hao control = LEAPRAID_SCSIIO_CTRL_READ;
8515597088cSDongdong Hao break;
8525597088cSDongdong Hao case DMA_TO_DEVICE:
8535597088cSDongdong Hao control = LEAPRAID_SCSIIO_CTRL_WRITE;
8545597088cSDongdong Hao break;
8555597088cSDongdong Hao default:
8565597088cSDongdong Hao control = LEAPRAID_SCSIIO_CTRL_NODATATRANSFER;
8575597088cSDongdong Hao break;
8585597088cSDongdong Hao }
8595597088cSDongdong Hao
8605597088cSDongdong Hao control |= LEAPRAID_SCSIIO_CTRL_SIMPLEQ;
8615597088cSDongdong Hao
862*46f861d3SDongdong Hao if (sdev_priv->ncq_prio_enable &&
8635597088cSDongdong Hao (IOPRIO_PRIO_CLASS(req_get_ioprio(scsi_cmd_to_rq(scmd))) ==
8645597088cSDongdong Hao IOPRIO_CLASS_RT))
8655597088cSDongdong Hao control |= LEAPRAID_SCSIIO_CTRL_CMDPRI;
8665597088cSDongdong Hao if (scmd->cmd_len == 32)
8675597088cSDongdong Hao control |= LEAPRAID_SCSIIO_CTRL_CDB_32BYTE <<
8685597088cSDongdong Hao LEAPRAID_SCSIIO_CTRL_CDB_LEN_SHIFT;
8695597088cSDongdong Hao
8705597088cSDongdong Hao return control;
8715597088cSDongdong Hao }
8725597088cSDongdong Hao
leapraid_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scmd)8735597088cSDongdong Hao enum scsi_qc_status leapraid_queuecommand(struct Scsi_Host *shost,
8745597088cSDongdong Hao struct scsi_cmnd *scmd)
8755597088cSDongdong Hao {
8765597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(scmd->device->host);
8775597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv = scmd->device->hostdata;
8785597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
8795597088cSDongdong Hao struct leapraid_scsiio_req *scsiio_req;
8805597088cSDongdong Hao u32 control;
8815597088cSDongdong Hao u16 taskid;
8825597088cSDongdong Hao u16 hdl;
8835597088cSDongdong Hao enum scsi_qc_status rc = 0;
8845597088cSDongdong Hao
8855597088cSDongdong Hao if (!leapraid_should_queuecommand(adapter, sdev_priv, scmd, &rc))
8865597088cSDongdong Hao return rc;
8875597088cSDongdong Hao
8885597088cSDongdong Hao starget_priv = sdev_priv->starget_priv;
8895597088cSDongdong Hao hdl = starget_priv->hdl;
8905597088cSDongdong Hao control = build_scsiio_req_control(scmd, sdev_priv);
8915597088cSDongdong Hao
8925597088cSDongdong Hao taskid = leapraid_alloc_scsiio_taskid(adapter, scmd);
8935597088cSDongdong Hao scsiio_req = leapraid_get_task_desc(adapter, taskid);
8945597088cSDongdong Hao
8955597088cSDongdong Hao scsiio_req->func = LEAPRAID_FUNC_SCSIIO;
8965597088cSDongdong Hao if (sdev_priv->starget_priv->flg & LEAPRAID_TGT_FLG_RAID_MEMBER)
8975597088cSDongdong Hao scsiio_req->func = LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH;
8985597088cSDongdong Hao else
8995597088cSDongdong Hao scsiio_req->func = LEAPRAID_FUNC_SCSIIO;
9005597088cSDongdong Hao
9015597088cSDongdong Hao scsiio_req->dev_hdl = cpu_to_le16(hdl);
9025597088cSDongdong Hao scsiio_req->data_len = cpu_to_le32(scsi_bufflen(scmd));
9035597088cSDongdong Hao scsiio_req->ctrl = cpu_to_le32(control);
9045597088cSDongdong Hao scsiio_req->io_flg = cpu_to_le16(scmd->cmd_len);
9055597088cSDongdong Hao scsiio_req->msg_flg = 0;
9065597088cSDongdong Hao scsiio_req->sense_buffer_len = SCSI_SENSE_BUFFERSIZE;
9075597088cSDongdong Hao scsiio_req->sense_buffer_low_add =
9085597088cSDongdong Hao leapraid_get_sense_buffer_dma(adapter, taskid);
9095597088cSDongdong Hao scsiio_req->sgl_offset0 =
9105597088cSDongdong Hao offsetof(struct leapraid_scsiio_req, sgl) /
9115597088cSDongdong Hao LEAPRAID_DWORDS_BYTE_SIZE;
9125597088cSDongdong Hao int_to_scsilun(sdev_priv->lun, (struct scsi_lun *)scsiio_req->lun);
9135597088cSDongdong Hao memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len);
9145597088cSDongdong Hao if (scsiio_req->data_len) {
9155597088cSDongdong Hao if (leapraid_build_scmd_ieee_sg(adapter, scmd, taskid)) {
9165597088cSDongdong Hao leapraid_free_taskid(adapter, taskid);
9175597088cSDongdong Hao return SCSI_MLQUEUE_HOST_BUSY;
9185597088cSDongdong Hao }
9195597088cSDongdong Hao } else {
9205597088cSDongdong Hao leapraid_build_ieee_nodata_sg(adapter, &scsiio_req->sgl);
9215597088cSDongdong Hao }
9225597088cSDongdong Hao
9235597088cSDongdong Hao if (likely(scsiio_req->func == LEAPRAID_FUNC_SCSIIO))
9245597088cSDongdong Hao leapraid_fire_scsi_io(adapter, taskid,
9255597088cSDongdong Hao le16_to_cpu(scsiio_req->dev_hdl));
9265597088cSDongdong Hao else
9275597088cSDongdong Hao leapraid_fire_task(adapter, taskid);
9285597088cSDongdong Hao
9295597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
9305597088cSDongdong Hao "LEAPRAID_SCSIIO: Send Descriptor taskid %d, req type 0x%x\n",
9315597088cSDongdong Hao taskid, scsiio_req->func);
9325597088cSDongdong Hao return rc;
9335597088cSDongdong Hao }
9345597088cSDongdong Hao
leapraid_init_cmd_priv(struct Scsi_Host * shost,struct scsi_cmnd * scmd)9355597088cSDongdong Hao static int leapraid_init_cmd_priv(struct Scsi_Host *shost,
9365597088cSDongdong Hao struct scsi_cmnd *scmd)
9375597088cSDongdong Hao {
9385597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
9395597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker;
9405597088cSDongdong Hao
9415597088cSDongdong Hao io_tracker = scsi_cmd_priv(scmd);
9425597088cSDongdong Hao leapraid_internal_init_cmd_priv(adapter, io_tracker);
9435597088cSDongdong Hao
9445597088cSDongdong Hao return 0;
9455597088cSDongdong Hao }
9465597088cSDongdong Hao
leapraid_exit_cmd_priv(struct Scsi_Host * shost,struct scsi_cmnd * scmd)9475597088cSDongdong Hao static int leapraid_exit_cmd_priv(struct Scsi_Host *shost,
9485597088cSDongdong Hao struct scsi_cmnd *scmd)
9495597088cSDongdong Hao {
9505597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
9515597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker;
9525597088cSDongdong Hao
9535597088cSDongdong Hao io_tracker = scsi_cmd_priv(scmd);
9545597088cSDongdong Hao leapraid_internal_exit_cmd_priv(adapter, io_tracker);
9555597088cSDongdong Hao
9565597088cSDongdong Hao return 0;
9575597088cSDongdong Hao }
9585597088cSDongdong Hao
leapraid_error_handler(struct scsi_cmnd * scmd,const char * str,u8 type)9595597088cSDongdong Hao static int leapraid_error_handler(struct scsi_cmnd *scmd,
9605597088cSDongdong Hao const char *str, u8 type)
9615597088cSDongdong Hao {
9625597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(scmd->device->host);
9635597088cSDongdong Hao struct scsi_target *starget = scmd->device->sdev_target;
9645597088cSDongdong Hao struct leapraid_starget_priv *starget_priv = starget->hostdata;
9655597088cSDongdong Hao struct leapraid_io_req_tracker *io_req_tracker = NULL;
9665597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
9675597088cSDongdong Hao struct leapraid_sas_dev *sas_dev = NULL;
9685597088cSDongdong Hao u16 hdl;
9695597088cSDongdong Hao int rc;
9705597088cSDongdong Hao
9715597088cSDongdong Hao dev_info(&adapter->pdev->dev,
9725597088cSDongdong Hao "EH enter: type=%s, scmd=0x%p, req tag=%d\n", str, scmd,
9735597088cSDongdong Hao scsi_cmd_to_rq(scmd)->tag);
9745597088cSDongdong Hao scsi_print_command(scmd);
9755597088cSDongdong Hao
9765597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK) {
9775597088cSDongdong Hao io_req_tracker = scsi_cmd_priv(scmd);
9785597088cSDongdong Hao dev_info(&adapter->pdev->dev,
9795597088cSDongdong Hao "EH ABORT: scmd=0x%p, pend=%ums, tout=%ums, tag=%d\n",
9805597088cSDongdong Hao scmd,
9815597088cSDongdong Hao jiffies_to_msecs(jiffies - scmd->jiffies_at_alloc),
9825597088cSDongdong Hao (scsi_cmd_to_rq(scmd)->timeout / HZ) * 1000,
9835597088cSDongdong Hao scsi_cmd_to_rq(scmd)->tag);
9845597088cSDongdong Hao }
9855597088cSDongdong Hao
9865597088cSDongdong Hao if (leapraid_pci_removed(adapter) ||
9875597088cSDongdong Hao adapter->access_ctrl.host_removing) {
9885597088cSDongdong Hao dev_err(&adapter->pdev->dev,
9895597088cSDongdong Hao "EH %s failed: %s scmd=0x%p\n", str,
9905597088cSDongdong Hao (adapter->access_ctrl.host_removing ?
9915597088cSDongdong Hao "shost removing!" : "pci_dev removed!"), scmd);
9925597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK &&
9935597088cSDongdong Hao io_req_tracker && io_req_tracker->taskid)
9945597088cSDongdong Hao leapraid_free_taskid(adapter, io_req_tracker->taskid);
9955597088cSDongdong Hao scmd->result = DID_NO_CONNECT << LEAPRAID_SCSI_HOST_SHIFT;
9965597088cSDongdong Hao #ifdef FAST_IO_FAIL
9975597088cSDongdong Hao rc = FAST_IO_FAIL;
9985597088cSDongdong Hao #else
9995597088cSDongdong Hao rc = FAILED;
10005597088cSDongdong Hao #endif
10015597088cSDongdong Hao goto out_eh_done;
10025597088cSDongdong Hao }
10035597088cSDongdong Hao
10045597088cSDongdong Hao sdev_priv = scmd->device->hostdata;
10055597088cSDongdong Hao if (!sdev_priv || !sdev_priv->starget_priv) {
10065597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
10075597088cSDongdong Hao "EH %s: SAS dev or starget gone, scmd=0x%p\n",
10085597088cSDongdong Hao str, scmd);
10095597088cSDongdong Hao scmd->result = DID_NO_CONNECT << LEAPRAID_SCSI_HOST_SHIFT;
10105597088cSDongdong Hao scsi_done(scmd);
10115597088cSDongdong Hao rc = SUCCESS;
10125597088cSDongdong Hao goto out_eh_done;
10135597088cSDongdong Hao }
10145597088cSDongdong Hao
10155597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK) {
10165597088cSDongdong Hao if (!io_req_tracker) {
10175597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
10185597088cSDongdong Hao "EH ABORT: No I/O tracker, scmd 0x%p\n", scmd);
10195597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
10205597088cSDongdong Hao rc = SUCCESS;
10215597088cSDongdong Hao goto out_eh_done;
10225597088cSDongdong Hao }
10235597088cSDongdong Hao
10245597088cSDongdong Hao if (sdev_priv->starget_priv->flg &
10255597088cSDongdong Hao LEAPRAID_TGT_FLG_RAID_MEMBER ||
10265597088cSDongdong Hao sdev_priv->starget_priv->flg & LEAPRAID_TGT_FLG_VOLUME) {
10275597088cSDongdong Hao dev_err(&adapter->pdev->dev,
10285597088cSDongdong Hao "EH ABORT: Skip RAID/VOLUME, scmd=0x%p\n",
10295597088cSDongdong Hao scmd);
10305597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
10315597088cSDongdong Hao rc = FAILED;
10325597088cSDongdong Hao goto out_eh_done;
10335597088cSDongdong Hao }
10345597088cSDongdong Hao
10355597088cSDongdong Hao hdl = sdev_priv->starget_priv->hdl;
10365597088cSDongdong Hao } else {
10375597088cSDongdong Hao hdl = 0;
10385597088cSDongdong Hao if (sdev_priv->starget_priv->flg &
10395597088cSDongdong Hao LEAPRAID_TGT_FLG_RAID_MEMBER) {
10405597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_from_tgt(adapter,
10415597088cSDongdong Hao starget_priv);
10425597088cSDongdong Hao if (sas_dev)
10435597088cSDongdong Hao hdl = sas_dev->volume_hdl;
10445597088cSDongdong Hao } else {
10455597088cSDongdong Hao hdl = sdev_priv->starget_priv->hdl;
10465597088cSDongdong Hao }
10475597088cSDongdong Hao
10485597088cSDongdong Hao if (!hdl) {
10495597088cSDongdong Hao dev_err(&adapter->pdev->dev,
10505597088cSDongdong Hao "EH %s failed: Target handle 0, scmd=0x%p\n",
10515597088cSDongdong Hao str, scmd);
10525597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
10535597088cSDongdong Hao rc = FAILED;
10545597088cSDongdong Hao goto out_eh_done;
10555597088cSDongdong Hao }
10565597088cSDongdong Hao }
10575597088cSDongdong Hao
10585597088cSDongdong Hao dev_info(&adapter->pdev->dev,
10595597088cSDongdong Hao "EH issue TM: type=%s, scmd=0x%p, hdl=0x%x\n",
10605597088cSDongdong Hao str, scmd, hdl);
10615597088cSDongdong Hao
10625597088cSDongdong Hao rc = leapraid_issue_locked_tm(
10635597088cSDongdong Hao adapter,
10645597088cSDongdong Hao hdl,
10655597088cSDongdong Hao scmd->device->channel,
10665597088cSDongdong Hao scmd->device->id,
10675597088cSDongdong Hao (type == LEAPRAID_TM_TASKTYPE_TARGET_RESET ?
10685597088cSDongdong Hao 0 : scmd->device->lun),
10695597088cSDongdong Hao type,
10705597088cSDongdong Hao (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK ?
10715597088cSDongdong Hao io_req_tracker->taskid : 0),
10725597088cSDongdong Hao LEAPRAID_TM_MSGFLAGS_LINK_RESET);
10735597088cSDongdong Hao
10745597088cSDongdong Hao out_eh_done:
10755597088cSDongdong Hao if (type == LEAPRAID_TM_TASKTYPE_ABORT_TASK) {
10765597088cSDongdong Hao if (rc != SUCCESS)
10775597088cSDongdong Hao dev_err(&adapter->pdev->dev,
10785597088cSDongdong Hao "EH ABORT result: failed, scmd=0x%p\n",
10795597088cSDongdong Hao scmd);
10805597088cSDongdong Hao } else {
10815597088cSDongdong Hao if (rc != SUCCESS)
10825597088cSDongdong Hao dev_err(&adapter->pdev->dev,
10835597088cSDongdong Hao "EH %s result: failed, scmd=0x%p\n",
10845597088cSDongdong Hao str, scmd);
10855597088cSDongdong Hao if (sas_dev)
10865597088cSDongdong Hao leapraid_sdev_put(sas_dev);
10875597088cSDongdong Hao }
10885597088cSDongdong Hao return rc;
10895597088cSDongdong Hao }
10905597088cSDongdong Hao
leapraid_eh_abort_handler(struct scsi_cmnd * scmd)10915597088cSDongdong Hao static int leapraid_eh_abort_handler(struct scsi_cmnd *scmd)
10925597088cSDongdong Hao {
10935597088cSDongdong Hao return leapraid_error_handler(scmd, "ABORT TASK",
10945597088cSDongdong Hao LEAPRAID_TM_TASKTYPE_ABORT_TASK);
10955597088cSDongdong Hao }
10965597088cSDongdong Hao
leapraid_eh_device_reset_handler(struct scsi_cmnd * scmd)10975597088cSDongdong Hao static int leapraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
10985597088cSDongdong Hao {
10995597088cSDongdong Hao return leapraid_error_handler(scmd, "UNIT RESET",
11005597088cSDongdong Hao LEAPRAID_TM_TASKTYPE_LOGICAL_UNIT_RESET);
11015597088cSDongdong Hao }
11025597088cSDongdong Hao
leapraid_eh_target_reset_handler(struct scsi_cmnd * scmd)11035597088cSDongdong Hao static int leapraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
11045597088cSDongdong Hao {
11055597088cSDongdong Hao return leapraid_error_handler(scmd, "TARGET RESET",
11065597088cSDongdong Hao LEAPRAID_TM_TASKTYPE_TARGET_RESET);
11075597088cSDongdong Hao }
11085597088cSDongdong Hao
leapraid_eh_host_reset_handler(struct scsi_cmnd * scmd)11095597088cSDongdong Hao static int leapraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
11105597088cSDongdong Hao {
11115597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(scmd->device->host);
11125597088cSDongdong Hao int rc;
11135597088cSDongdong Hao
11145597088cSDongdong Hao dev_info(&adapter->pdev->dev,
11155597088cSDongdong Hao "EH HOST RESET enter: scmd=%p, req tag=%d\n",
11165597088cSDongdong Hao scmd,
11175597088cSDongdong Hao scsi_cmd_to_rq(scmd)->tag);
11185597088cSDongdong Hao scsi_print_command(scmd);
11195597088cSDongdong Hao
11205597088cSDongdong Hao if (adapter->scan_dev_desc.driver_loading ||
11215597088cSDongdong Hao adapter->access_ctrl.host_removing) {
11225597088cSDongdong Hao dev_err(&adapter->pdev->dev,
11235597088cSDongdong Hao "EH HOST RESET failed: %s scmd=0x%p\n",
11245597088cSDongdong Hao (adapter->access_ctrl.host_removing ?
11255597088cSDongdong Hao "shost removing!" : "driver loading!"), scmd);
11265597088cSDongdong Hao rc = FAILED;
11275597088cSDongdong Hao goto out_host_reset_done;
11285597088cSDongdong Hao }
11295597088cSDongdong Hao
11305597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: Issuing hard reset\n",
11315597088cSDongdong Hao __func__, __LINE__);
11325597088cSDongdong Hao if (leapraid_hard_reset_handler(adapter, FULL_RESET) < 0)
11335597088cSDongdong Hao rc = FAILED;
11345597088cSDongdong Hao else
11355597088cSDongdong Hao rc = SUCCESS;
11365597088cSDongdong Hao
11375597088cSDongdong Hao out_host_reset_done:
11385597088cSDongdong Hao if (rc != SUCCESS)
11395597088cSDongdong Hao dev_err(&adapter->pdev->dev,
11405597088cSDongdong Hao "EH HOST RESET result: failed, scmd=0x%p\n",
11415597088cSDongdong Hao scmd);
11425597088cSDongdong Hao return rc;
11435597088cSDongdong Hao }
11445597088cSDongdong Hao
leapraid_sdev_init(struct scsi_device * sdev)11455597088cSDongdong Hao static int leapraid_sdev_init(struct scsi_device *sdev)
11465597088cSDongdong Hao {
11475597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
11485597088cSDongdong Hao struct leapraid_starget_priv *stgt_priv;
11495597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
11505597088cSDongdong Hao struct leapraid_adapter *adapter;
11515597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
11525597088cSDongdong Hao struct scsi_target *tgt;
11535597088cSDongdong Hao struct Scsi_Host *shost;
11545597088cSDongdong Hao unsigned long flags;
11555597088cSDongdong Hao
11565597088cSDongdong Hao sdev_priv = kzalloc_obj(*sdev_priv);
11575597088cSDongdong Hao if (!sdev_priv)
11585597088cSDongdong Hao return -ENOMEM;
11595597088cSDongdong Hao
11605597088cSDongdong Hao sdev_priv->lun = sdev->lun;
11615597088cSDongdong Hao sdev_priv->flg = LEAPRAID_DEVICE_FLG_INIT;
11625597088cSDongdong Hao tgt = scsi_target(sdev);
11635597088cSDongdong Hao stgt_priv = tgt->hostdata;
11645597088cSDongdong Hao stgt_priv->num_luns++;
11655597088cSDongdong Hao sdev_priv->starget_priv = stgt_priv;
11665597088cSDongdong Hao sdev->hostdata = sdev_priv;
11675597088cSDongdong Hao if (stgt_priv->flg & LEAPRAID_TGT_FLG_RAID_MEMBER)
11685597088cSDongdong Hao sdev->no_uld_attach = LEAPRAID_NO_ULD_ATTACH;
11695597088cSDongdong Hao
11705597088cSDongdong Hao shost = dev_to_shost(&tgt->dev);
11715597088cSDongdong Hao adapter = shost_priv(shost);
11725597088cSDongdong Hao if (tgt->channel == RAID_CHANNEL) {
11735597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_id(adapter,
11745597088cSDongdong Hao tgt->id,
11755597088cSDongdong Hao tgt->channel);
11765597088cSDongdong Hao if (raid_volume) {
11775597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock,
11785597088cSDongdong Hao flags);
11795597088cSDongdong Hao raid_volume->sdev = sdev;
11805597088cSDongdong Hao spin_unlock_irqrestore(
11815597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
11825597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
11835597088cSDongdong Hao }
11845597088cSDongdong Hao }
11855597088cSDongdong Hao
11865597088cSDongdong Hao if (!(stgt_priv->flg & LEAPRAID_TGT_FLG_VOLUME)) {
11875597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
11885597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(
11895597088cSDongdong Hao adapter,
11905597088cSDongdong Hao stgt_priv->sas_address,
11915597088cSDongdong Hao stgt_priv->card_port);
11925597088cSDongdong Hao if (sas_dev && !sas_dev->starget) {
11935597088cSDongdong Hao sdev_printk(KERN_INFO, sdev,
11945597088cSDongdong Hao "%s: Assign starget to sas_dev\n",
11955597088cSDongdong Hao __func__);
11965597088cSDongdong Hao sas_dev->starget = tgt;
11975597088cSDongdong Hao }
11985597088cSDongdong Hao
11995597088cSDongdong Hao if (sas_dev)
12005597088cSDongdong Hao leapraid_sdev_put(sas_dev);
12015597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
12025597088cSDongdong Hao }
12035597088cSDongdong Hao return 0;
12045597088cSDongdong Hao }
12055597088cSDongdong Hao
leapraid_slave_cfg_volume(struct scsi_device * sdev,struct queue_limits * lim)12065597088cSDongdong Hao static bool leapraid_slave_cfg_volume(struct scsi_device *sdev,
12075597088cSDongdong Hao struct queue_limits *lim)
12085597088cSDongdong Hao {
12095597088cSDongdong Hao struct Scsi_Host *shost = sdev->host;
12105597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
12115597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
12125597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
12135597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
12145597088cSDongdong Hao int qd;
12155597088cSDongdong Hao u16 hdl;
12165597088cSDongdong Hao
12175597088cSDongdong Hao sdev_priv = sdev->hostdata;
12185597088cSDongdong Hao starget_priv = sdev_priv->starget_priv;
12195597088cSDongdong Hao hdl = starget_priv->hdl;
12205597088cSDongdong Hao
12215597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_hdl(adapter, hdl);
12225597088cSDongdong Hao if (!raid_volume) {
12235597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
12245597088cSDongdong Hao "%s: RAID volume not found, hdl=0x%x\n",
12255597088cSDongdong Hao __func__, hdl);
12265597088cSDongdong Hao return 1;
12275597088cSDongdong Hao }
12285597088cSDongdong Hao
12295597088cSDongdong Hao if (leapraid_get_volume_cap(adapter, raid_volume)) {
12305597088cSDongdong Hao sdev_printk(KERN_ERR, sdev,
12315597088cSDongdong Hao "%s: Failed to get volume cap, hdl=0x%x\n",
12325597088cSDongdong Hao __func__, hdl);
12335597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
12345597088cSDongdong Hao return 1;
12355597088cSDongdong Hao }
12365597088cSDongdong Hao
12375597088cSDongdong Hao qd = (raid_volume->dev_info & LEAPRAID_DEVTYP_SSP_TGT) ?
12385597088cSDongdong Hao adapter->adapter_attr.narrowport_max_queue_depth :
12395597088cSDongdong Hao adapter->adapter_attr.sata_max_queue_depth;
12405597088cSDongdong Hao if (raid_volume->vol_type != LEAPRAID_VOL_TYPE_RAID0)
12415597088cSDongdong Hao qd = adapter->adapter_attr.raid_volume_max_queue_depth;
12425597088cSDongdong Hao
12435597088cSDongdong Hao sdev_printk(KERN_INFO, sdev,
12445597088cSDongdong Hao "RAID volume: hdl=0x%04x, wwid=0x%016llx\n",
12455597088cSDongdong Hao raid_volume->hdl, (unsigned long long)raid_volume->wwid);
12465597088cSDongdong Hao
12475597088cSDongdong Hao if (shost->max_sectors > LEAPRAID_MAX_SECTORS)
12485597088cSDongdong Hao lim->max_hw_sectors = LEAPRAID_MAX_SECTORS;
12495597088cSDongdong Hao
12505597088cSDongdong Hao leapraid_change_queue_depth(sdev, qd);
12515597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
12525597088cSDongdong Hao return 0;
12535597088cSDongdong Hao }
12545597088cSDongdong Hao
leapraid_slave_configure_extra(struct scsi_device * sdev,struct leapraid_sas_dev ** psas_dev,u16 vol_hdl,u64 volume_wwid,bool * is_target_ssp,int * qd)12555597088cSDongdong Hao static bool leapraid_slave_configure_extra(struct scsi_device *sdev,
12565597088cSDongdong Hao struct leapraid_sas_dev **psas_dev,
12575597088cSDongdong Hao u16 vol_hdl, u64 volume_wwid,
12585597088cSDongdong Hao bool *is_target_ssp, int *qd)
12595597088cSDongdong Hao {
12605597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
12615597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
12625597088cSDongdong Hao struct Scsi_Host *shost = sdev->host;
12635597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
12645597088cSDongdong Hao unsigned long flags;
12655597088cSDongdong Hao
12665597088cSDongdong Hao sdev_priv = sdev->hostdata;
12675597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
12685597088cSDongdong Hao *is_target_ssp = false;
12695597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(
12705597088cSDongdong Hao adapter,
12715597088cSDongdong Hao sdev_priv->starget_priv->sas_address,
12725597088cSDongdong Hao sdev_priv->starget_priv->card_port);
12735597088cSDongdong Hao if (!sas_dev) {
12745597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
12755597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
12765597088cSDongdong Hao "%s: SAS dev not found, sas=0x%llx\n",
12775597088cSDongdong Hao __func__, sdev_priv->starget_priv->sas_address);
12785597088cSDongdong Hao return 1;
12795597088cSDongdong Hao }
12805597088cSDongdong Hao
12815597088cSDongdong Hao *psas_dev = sas_dev;
12825597088cSDongdong Hao sas_dev->volume_hdl = vol_hdl;
12835597088cSDongdong Hao sas_dev->volume_wwid = volume_wwid;
12845597088cSDongdong Hao if (sas_dev->dev_info & LEAPRAID_DEVTYP_SSP_TGT) {
12855597088cSDongdong Hao *qd = (sas_dev->port_connection > 1) ?
12865597088cSDongdong Hao adapter->adapter_attr.wideport_max_queue_depth :
12875597088cSDongdong Hao adapter->adapter_attr.narrowport_max_queue_depth;
12885597088cSDongdong Hao *is_target_ssp = true;
12895597088cSDongdong Hao if (sas_dev->dev_info & LEAPRAID_DEVTYP_SEP)
12905597088cSDongdong Hao sdev_priv->sep = 1;
12915597088cSDongdong Hao } else {
12925597088cSDongdong Hao *qd = adapter->adapter_attr.sata_max_queue_depth;
12935597088cSDongdong Hao }
12945597088cSDongdong Hao
12955597088cSDongdong Hao sdev_printk(KERN_INFO, sdev,
12965597088cSDongdong Hao "device name=0x%016llx, SAS addr=0x%016llx\n",
12975597088cSDongdong Hao (unsigned long long)sas_dev->dev_name,
12985597088cSDongdong Hao (unsigned long long)sas_dev->sas_addr);
12995597088cSDongdong Hao leapraid_sdev_put(sas_dev);
13005597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
13015597088cSDongdong Hao return 0;
13025597088cSDongdong Hao }
13035597088cSDongdong Hao
leapraid_sdev_configure(struct scsi_device * sdev,struct queue_limits * lim)13045597088cSDongdong Hao static int leapraid_sdev_configure(struct scsi_device *sdev,
13055597088cSDongdong Hao struct queue_limits *lim)
13065597088cSDongdong Hao {
13075597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
13085597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
13095597088cSDongdong Hao struct Scsi_Host *shost = sdev->host;
13105597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
13115597088cSDongdong Hao struct leapraid_adapter *adapter;
13125597088cSDongdong Hao u16 hdl, vol_hdl = 0;
13135597088cSDongdong Hao bool is_target_ssp = false;
13145597088cSDongdong Hao u64 volume_wwid = 0;
13155597088cSDongdong Hao int qd = 1;
13165597088cSDongdong Hao
13175597088cSDongdong Hao adapter = shost_priv(shost);
13185597088cSDongdong Hao sdev_priv = sdev->hostdata;
13195597088cSDongdong Hao sdev_priv->flg &= ~LEAPRAID_DEVICE_FLG_INIT;
13205597088cSDongdong Hao starget_priv = sdev_priv->starget_priv;
13215597088cSDongdong Hao hdl = starget_priv->hdl;
13225597088cSDongdong Hao if (starget_priv->flg & LEAPRAID_TGT_FLG_VOLUME)
13235597088cSDongdong Hao return leapraid_slave_cfg_volume(sdev, lim);
13245597088cSDongdong Hao
13255597088cSDongdong Hao if (starget_priv->flg & LEAPRAID_TGT_FLG_RAID_MEMBER) {
13265597088cSDongdong Hao if (leapraid_cfg_get_volume_hdl(adapter, hdl, &vol_hdl)) {
13275597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
13285597088cSDongdong Hao "%s: Get volume hdl failed, hdl=0x%x\n",
13295597088cSDongdong Hao __func__, hdl);
13305597088cSDongdong Hao return 1;
13315597088cSDongdong Hao }
13325597088cSDongdong Hao
13335597088cSDongdong Hao if (vol_hdl && leapraid_cfg_get_volume_wwid(adapter, vol_hdl,
13345597088cSDongdong Hao &volume_wwid)) {
13355597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
13365597088cSDongdong Hao "%s: Get wwid failed, volume_hdl=0x%x\n",
13375597088cSDongdong Hao __func__, vol_hdl);
13385597088cSDongdong Hao return 1;
13395597088cSDongdong Hao }
13405597088cSDongdong Hao }
13415597088cSDongdong Hao
13425597088cSDongdong Hao if (leapraid_slave_configure_extra(sdev, &sas_dev, vol_hdl,
13435597088cSDongdong Hao volume_wwid, &is_target_ssp, &qd)) {
13445597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
13455597088cSDongdong Hao "%s: slave_configure_extra failed\n", __func__);
13465597088cSDongdong Hao return 1;
13475597088cSDongdong Hao }
13485597088cSDongdong Hao
13495597088cSDongdong Hao leapraid_change_queue_depth(sdev, qd);
13505597088cSDongdong Hao if (is_target_ssp)
13515597088cSDongdong Hao sas_read_port_mode_page(sdev);
13525597088cSDongdong Hao
13535597088cSDongdong Hao return 0;
13545597088cSDongdong Hao }
13555597088cSDongdong Hao
leapraid_sdev_destroy(struct scsi_device * sdev)13565597088cSDongdong Hao static void leapraid_sdev_destroy(struct scsi_device *sdev)
13575597088cSDongdong Hao {
13585597088cSDongdong Hao struct leapraid_adapter *adapter;
13595597088cSDongdong Hao struct Scsi_Host *shost;
13605597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
13615597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
13625597088cSDongdong Hao struct scsi_target *stgt;
13635597088cSDongdong Hao unsigned long flags;
13645597088cSDongdong Hao
13655597088cSDongdong Hao if (!sdev->hostdata)
13665597088cSDongdong Hao return;
13675597088cSDongdong Hao
13685597088cSDongdong Hao stgt = scsi_target(sdev);
13695597088cSDongdong Hao starget_priv = stgt->hostdata;
13705597088cSDongdong Hao starget_priv->num_luns--;
13715597088cSDongdong Hao shost = dev_to_shost(&stgt->dev);
13725597088cSDongdong Hao adapter = shost_priv(shost);
13735597088cSDongdong Hao if (!(starget_priv->flg & LEAPRAID_TGT_FLG_VOLUME)) {
13745597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
13755597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_from_tgt(adapter,
13765597088cSDongdong Hao starget_priv);
13775597088cSDongdong Hao if (sas_dev && !starget_priv->num_luns)
13785597088cSDongdong Hao sas_dev->starget = NULL;
13795597088cSDongdong Hao if (sas_dev)
13805597088cSDongdong Hao leapraid_sdev_put(sas_dev);
13815597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
13825597088cSDongdong Hao }
13835597088cSDongdong Hao
13845597088cSDongdong Hao kfree(sdev->hostdata);
13855597088cSDongdong Hao sdev->hostdata = NULL;
13865597088cSDongdong Hao }
13875597088cSDongdong Hao
leapraid_target_alloc_raid(struct scsi_target * tgt)13885597088cSDongdong Hao static int leapraid_target_alloc_raid(struct scsi_target *tgt)
13895597088cSDongdong Hao {
13905597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
13915597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
13925597088cSDongdong Hao struct Scsi_Host *shost = dev_to_shost(&tgt->dev);
13935597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
13945597088cSDongdong Hao unsigned long flags;
13955597088cSDongdong Hao
13965597088cSDongdong Hao starget_priv = tgt->hostdata;
13975597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_id(adapter, tgt->id,
13985597088cSDongdong Hao tgt->channel);
13995597088cSDongdong Hao if (raid_volume) {
14005597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
14015597088cSDongdong Hao starget_priv->hdl = raid_volume->hdl;
14025597088cSDongdong Hao starget_priv->sas_address = raid_volume->wwid;
14035597088cSDongdong Hao starget_priv->flg |= LEAPRAID_TGT_FLG_VOLUME;
14045597088cSDongdong Hao raid_volume->starget = tgt;
14055597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
14065597088cSDongdong Hao flags);
14075597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
14085597088cSDongdong Hao }
14095597088cSDongdong Hao return 0;
14105597088cSDongdong Hao }
14115597088cSDongdong Hao
leapraid_target_alloc_sas(struct scsi_target * tgt)14125597088cSDongdong Hao static int leapraid_target_alloc_sas(struct scsi_target *tgt)
14135597088cSDongdong Hao {
14145597088cSDongdong Hao struct sas_rphy *rphy;
14155597088cSDongdong Hao struct Scsi_Host *shost;
14165597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
14175597088cSDongdong Hao struct leapraid_adapter *adapter;
14185597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
14195597088cSDongdong Hao unsigned long flags;
14205597088cSDongdong Hao
14215597088cSDongdong Hao shost = dev_to_shost(&tgt->dev);
14225597088cSDongdong Hao adapter = shost_priv(shost);
14235597088cSDongdong Hao starget_priv = tgt->hostdata;
14245597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
14255597088cSDongdong Hao rphy = dev_to_rphy(tgt->dev.parent);
14265597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr_and_rphy(
14275597088cSDongdong Hao adapter,
14285597088cSDongdong Hao rphy->identify.sas_address,
14295597088cSDongdong Hao rphy);
14305597088cSDongdong Hao if (sas_dev) {
14315597088cSDongdong Hao starget_priv->sas_dev = sas_dev;
14325597088cSDongdong Hao starget_priv->card_port = sas_dev->card_port;
14335597088cSDongdong Hao starget_priv->sas_address = sas_dev->sas_addr;
14345597088cSDongdong Hao starget_priv->hdl = sas_dev->hdl;
14355597088cSDongdong Hao sas_dev->channel = tgt->channel;
14365597088cSDongdong Hao sas_dev->id = tgt->id;
14375597088cSDongdong Hao sas_dev->starget = tgt;
14385597088cSDongdong Hao if (sas_dev->hdl &&
14395597088cSDongdong Hao sas_dev->hdl <=
14405597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle &&
14415597088cSDongdong Hao test_bit(sas_dev->hdl, adapter->dev_topo.pd_hdls))
14425597088cSDongdong Hao starget_priv->flg |= LEAPRAID_TGT_FLG_RAID_MEMBER;
14435597088cSDongdong Hao }
14445597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
14455597088cSDongdong Hao
14465597088cSDongdong Hao return 0;
14475597088cSDongdong Hao }
14485597088cSDongdong Hao
leapraid_target_alloc(struct scsi_target * tgt)14495597088cSDongdong Hao static int leapraid_target_alloc(struct scsi_target *tgt)
14505597088cSDongdong Hao {
14515597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
14525597088cSDongdong Hao
14535597088cSDongdong Hao starget_priv = kzalloc_obj(*starget_priv);
14545597088cSDongdong Hao if (!starget_priv)
14555597088cSDongdong Hao return -ENOMEM;
14565597088cSDongdong Hao
14575597088cSDongdong Hao tgt->hostdata = starget_priv;
14585597088cSDongdong Hao starget_priv->starget = tgt;
14595597088cSDongdong Hao starget_priv->hdl = LEAPRAID_INVALID_DEV_HANDLE;
14605597088cSDongdong Hao if (tgt->channel == RAID_CHANNEL)
14615597088cSDongdong Hao return leapraid_target_alloc_raid(tgt);
14625597088cSDongdong Hao
14635597088cSDongdong Hao return leapraid_target_alloc_sas(tgt);
14645597088cSDongdong Hao }
14655597088cSDongdong Hao
leapraid_target_destroy_raid(struct scsi_target * tgt)14665597088cSDongdong Hao static void leapraid_target_destroy_raid(struct scsi_target *tgt)
14675597088cSDongdong Hao {
14685597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
14695597088cSDongdong Hao struct Scsi_Host *shost = dev_to_shost(&tgt->dev);
14705597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
14715597088cSDongdong Hao unsigned long flags;
14725597088cSDongdong Hao
14735597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_id(adapter, tgt->id,
14745597088cSDongdong Hao tgt->channel);
14755597088cSDongdong Hao if (raid_volume) {
14765597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
14775597088cSDongdong Hao raid_volume->starget = NULL;
14785597088cSDongdong Hao raid_volume->sdev = NULL;
14795597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
14805597088cSDongdong Hao flags);
14815597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
14825597088cSDongdong Hao }
14835597088cSDongdong Hao }
14845597088cSDongdong Hao
leapraid_target_destroy_sas(struct scsi_target * tgt)14855597088cSDongdong Hao static void leapraid_target_destroy_sas(struct scsi_target *tgt)
14865597088cSDongdong Hao {
14875597088cSDongdong Hao struct leapraid_adapter *adapter;
14885597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
14895597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
14905597088cSDongdong Hao struct Scsi_Host *shost;
14915597088cSDongdong Hao unsigned long flags;
14925597088cSDongdong Hao
14935597088cSDongdong Hao shost = dev_to_shost(&tgt->dev);
14945597088cSDongdong Hao adapter = shost_priv(shost);
14955597088cSDongdong Hao starget_priv = tgt->hostdata;
14965597088cSDongdong Hao
14975597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
14985597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_from_tgt(adapter,
14995597088cSDongdong Hao starget_priv);
15005597088cSDongdong Hao if (sas_dev &&
15015597088cSDongdong Hao sas_dev->starget == tgt &&
15025597088cSDongdong Hao sas_dev->id == tgt->id &&
15035597088cSDongdong Hao sas_dev->channel == tgt->channel)
15045597088cSDongdong Hao sas_dev->starget = NULL;
15055597088cSDongdong Hao
15065597088cSDongdong Hao if (sas_dev) {
15075597088cSDongdong Hao starget_priv->sas_dev = NULL;
15085597088cSDongdong Hao leapraid_sdev_put(sas_dev);
15095597088cSDongdong Hao leapraid_sdev_put(sas_dev);
15105597088cSDongdong Hao }
15115597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
15125597088cSDongdong Hao }
15135597088cSDongdong Hao
leapraid_target_destroy(struct scsi_target * tgt)15145597088cSDongdong Hao static void leapraid_target_destroy(struct scsi_target *tgt)
15155597088cSDongdong Hao {
15165597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
15175597088cSDongdong Hao
15185597088cSDongdong Hao starget_priv = tgt->hostdata;
15195597088cSDongdong Hao if (!starget_priv)
15205597088cSDongdong Hao return;
15215597088cSDongdong Hao
15225597088cSDongdong Hao if (tgt->channel == RAID_CHANNEL) {
15235597088cSDongdong Hao leapraid_target_destroy_raid(tgt);
15245597088cSDongdong Hao goto out_free;
15255597088cSDongdong Hao }
15265597088cSDongdong Hao
15275597088cSDongdong Hao leapraid_target_destroy_sas(tgt);
15285597088cSDongdong Hao
15295597088cSDongdong Hao out_free:
15305597088cSDongdong Hao kfree(starget_priv);
15315597088cSDongdong Hao tgt->hostdata = NULL;
15325597088cSDongdong Hao }
15335597088cSDongdong Hao
leapraid_scan_check_status(struct leapraid_adapter * adapter,bool * need_hard_reset)15345597088cSDongdong Hao static bool leapraid_scan_check_status(struct leapraid_adapter *adapter,
15355597088cSDongdong Hao bool *need_hard_reset)
15365597088cSDongdong Hao {
15375597088cSDongdong Hao u32 adapter_state;
15385597088cSDongdong Hao
15395597088cSDongdong Hao if (adapter->scan_dev_desc.scan_start) {
15405597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
15415597088cSDongdong Hao if (adapter_state == LEAPRAID_DB_FAULT) {
15425597088cSDongdong Hao *need_hard_reset = true;
15435597088cSDongdong Hao return true;
15445597088cSDongdong Hao }
15455597088cSDongdong Hao return false;
15465597088cSDongdong Hao }
15475597088cSDongdong Hao
15485597088cSDongdong Hao if (adapter->driver_cmds.scan_dev_cmd.status & LEAPRAID_CMD_RESET) {
15495597088cSDongdong Hao dev_err(&adapter->pdev->dev,
15505597088cSDongdong Hao "Device scan: Aborted due to reset\n");
15515597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status =
15525597088cSDongdong Hao LEAPRAID_CMD_NOT_USED;
15535597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
15545597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
15555597088cSDongdong Hao return true;
15565597088cSDongdong Hao }
15575597088cSDongdong Hao
15585597088cSDongdong Hao if (adapter->scan_dev_desc.scan_start_failed) {
15595597088cSDongdong Hao dev_err(&adapter->pdev->dev,
15605597088cSDongdong Hao "Device scan: Failed with adapter_status=0x%08x\n",
15615597088cSDongdong Hao adapter->scan_dev_desc.scan_start_failed);
15625597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
15635597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
15645597088cSDongdong Hao adapter->scan_dev_desc.wait_scan_dev_done = 0;
15655597088cSDongdong Hao adapter->access_ctrl.host_removing = 1;
15665597088cSDongdong Hao return true;
15675597088cSDongdong Hao }
15685597088cSDongdong Hao
15695597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status = LEAPRAID_CMD_NOT_USED;
15705597088cSDongdong Hao leapraid_scan_dev_done(adapter);
15715597088cSDongdong Hao return true;
15725597088cSDongdong Hao }
15735597088cSDongdong Hao
leapraid_scan_finished(struct Scsi_Host * shost,unsigned long time)15745597088cSDongdong Hao static int leapraid_scan_finished(struct Scsi_Host *shost, unsigned long time)
15755597088cSDongdong Hao {
15765597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
15775597088cSDongdong Hao bool need_hard_reset = false;
15785597088cSDongdong Hao
15795597088cSDongdong Hao if (time >= (LEAPRAID_SCAN_DEV_CMD_TIMEOUT * HZ)) {
15805597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status =
15815597088cSDongdong Hao LEAPRAID_CMD_NOT_USED;
15825597088cSDongdong Hao dev_err(&adapter->pdev->dev,
15835597088cSDongdong Hao "Device scan: Failed with timeout 300s\n");
15845597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
15855597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
15865597088cSDongdong Hao return 1;
15875597088cSDongdong Hao }
15885597088cSDongdong Hao
15895597088cSDongdong Hao if (!leapraid_scan_check_status(adapter, &need_hard_reset))
15905597088cSDongdong Hao return 0;
15915597088cSDongdong Hao
15925597088cSDongdong Hao if (need_hard_reset) {
15935597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status =
15945597088cSDongdong Hao LEAPRAID_CMD_NOT_USED;
15955597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
15965597088cSDongdong Hao __func__, __LINE__);
15975597088cSDongdong Hao if (leapraid_hard_reset_handler(adapter, PART_RESET)) {
15985597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
15995597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
16005597088cSDongdong Hao }
16015597088cSDongdong Hao }
16025597088cSDongdong Hao
16035597088cSDongdong Hao return 1;
16045597088cSDongdong Hao }
16055597088cSDongdong Hao
leapraid_scan_start(struct Scsi_Host * shost)16065597088cSDongdong Hao static void leapraid_scan_start(struct Scsi_Host *shost)
16075597088cSDongdong Hao {
16085597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
16095597088cSDongdong Hao
16105597088cSDongdong Hao adapter->scan_dev_desc.scan_start = 1;
16115597088cSDongdong Hao leapraid_scan_dev(adapter, true);
16125597088cSDongdong Hao }
16135597088cSDongdong Hao
leapraid_get_raid_qd(struct leapraid_adapter * adapter,const struct leapraid_raid_volume * raid_volume,bool default_qd)16145597088cSDongdong Hao static u32 leapraid_get_raid_qd(struct leapraid_adapter *adapter,
16155597088cSDongdong Hao const struct leapraid_raid_volume *raid_volume,
16165597088cSDongdong Hao bool default_qd)
16175597088cSDongdong Hao {
16185597088cSDongdong Hao const struct leapraid_adapter_attr *attr = &adapter->adapter_attr;
16195597088cSDongdong Hao
16205597088cSDongdong Hao if (raid_volume->vol_type != LEAPRAID_VOL_TYPE_RAID0)
16215597088cSDongdong Hao return default_qd ? LEAPRAID_RAID_QUEUE_DEPTH :
16225597088cSDongdong Hao attr->raid_volume_max_queue_depth;
16235597088cSDongdong Hao
16245597088cSDongdong Hao if (raid_volume->dev_info & LEAPRAID_DEVTYP_SSP_TGT)
16255597088cSDongdong Hao return default_qd ? LEAPRAID_SAS_QUEUE_DEPTH :
16265597088cSDongdong Hao attr->narrowport_max_queue_depth;
16275597088cSDongdong Hao
16285597088cSDongdong Hao return default_qd ? LEAPRAID_SATA_QUEUE_DEPTH :
16295597088cSDongdong Hao attr->sata_max_queue_depth;
16305597088cSDongdong Hao }
16315597088cSDongdong Hao
leapraid_calc_max_queue_depth(struct scsi_device * sdev,int qdepth)16325597088cSDongdong Hao static int leapraid_calc_max_queue_depth(struct scsi_device *sdev, int qdepth)
16335597088cSDongdong Hao {
16345597088cSDongdong Hao struct Scsi_Host *shost;
16355597088cSDongdong Hao struct leapraid_adapter *adapter;
16365597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
16375597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
16385597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
16395597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
16405597088cSDongdong Hao int max_depth;
16415597088cSDongdong Hao u32 default_qdepth = 0;
16425597088cSDongdong Hao u32 fw_qdepth = 0;
16435597088cSDongdong Hao
16445597088cSDongdong Hao shost = sdev->host;
16455597088cSDongdong Hao adapter = shost_priv(shost);
16465597088cSDongdong Hao max_depth = shost->can_queue;
16475597088cSDongdong Hao
16485597088cSDongdong Hao sdev_priv = sdev->hostdata;
16495597088cSDongdong Hao if (!sdev_priv)
16505597088cSDongdong Hao goto out_tag_check;
16515597088cSDongdong Hao
16525597088cSDongdong Hao starget_priv = sdev_priv->starget_priv;
16535597088cSDongdong Hao if (!starget_priv)
16545597088cSDongdong Hao goto out_tag_check;
16555597088cSDongdong Hao
16565597088cSDongdong Hao if (starget_priv->flg & LEAPRAID_TGT_FLG_VOLUME) {
16575597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_hdl(
16585597088cSDongdong Hao adapter, starget_priv->hdl);
16595597088cSDongdong Hao if (raid_volume) {
16605597088cSDongdong Hao default_qdepth = leapraid_get_raid_qd(
16615597088cSDongdong Hao adapter, raid_volume, true);
16625597088cSDongdong Hao fw_qdepth = leapraid_get_raid_qd(
16635597088cSDongdong Hao adapter, raid_volume, false);
16645597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
16655597088cSDongdong Hao }
16665597088cSDongdong Hao goto out_limit_check;
16675597088cSDongdong Hao }
16685597088cSDongdong Hao
16695597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_from_tgt(adapter, starget_priv);
16705597088cSDongdong Hao if (sas_dev) {
16715597088cSDongdong Hao if (sas_dev->dev_info & LEAPRAID_DEVTYP_SSP_TGT) {
16725597088cSDongdong Hao default_qdepth = LEAPRAID_SAS_QUEUE_DEPTH;
16735597088cSDongdong Hao fw_qdepth = (sas_dev->port_connection > 1) ?
16745597088cSDongdong Hao adapter->adapter_attr.wideport_max_queue_depth :
16755597088cSDongdong Hao adapter->adapter_attr.narrowport_max_queue_depth;
16765597088cSDongdong Hao }
16775597088cSDongdong Hao if (sas_dev->dev_info & LEAPRAID_DEVTYP_SATA_DEV) {
16785597088cSDongdong Hao default_qdepth = LEAPRAID_SATA_QUEUE_DEPTH;
16795597088cSDongdong Hao fw_qdepth = adapter->adapter_attr.sata_max_queue_depth;
16805597088cSDongdong Hao }
16815597088cSDongdong Hao leapraid_sdev_put(sas_dev);
16825597088cSDongdong Hao }
16835597088cSDongdong Hao
16845597088cSDongdong Hao out_limit_check:
16855597088cSDongdong Hao if (fw_qdepth > shost->can_queue && default_qdepth)
16865597088cSDongdong Hao fw_qdepth = default_qdepth;
16875597088cSDongdong Hao
16885597088cSDongdong Hao if (fw_qdepth)
16895597088cSDongdong Hao max_depth = min_t(int, max_depth, fw_qdepth);
16905597088cSDongdong Hao
16915597088cSDongdong Hao out_tag_check:
16925597088cSDongdong Hao if (!sdev->tagged_supported)
16935597088cSDongdong Hao max_depth = 1;
16945597088cSDongdong Hao
16955597088cSDongdong Hao if (qdepth > max_depth)
16965597088cSDongdong Hao qdepth = max_depth;
16975597088cSDongdong Hao
16985597088cSDongdong Hao return qdepth;
16995597088cSDongdong Hao }
17005597088cSDongdong Hao
leapraid_change_queue_depth(struct scsi_device * sdev,int qdepth)17015597088cSDongdong Hao int leapraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
17025597088cSDongdong Hao {
17035597088cSDongdong Hao qdepth = leapraid_calc_max_queue_depth(sdev, qdepth);
17045597088cSDongdong Hao scsi_change_queue_depth(sdev, qdepth);
17055597088cSDongdong Hao return sdev->queue_depth;
17065597088cSDongdong Hao }
17075597088cSDongdong Hao
leapraid_map_queues(struct Scsi_Host * shost)17085597088cSDongdong Hao static void leapraid_map_queues(struct Scsi_Host *shost)
17095597088cSDongdong Hao {
17105597088cSDongdong Hao struct leapraid_adapter *adapter;
17115597088cSDongdong Hao struct blk_mq_queue_map *queue_map;
17125597088cSDongdong Hao int msix_queue_count;
17135597088cSDongdong Hao int poll_queue_count;
17145597088cSDongdong Hao int queue_offset;
17155597088cSDongdong Hao int map_index;
17165597088cSDongdong Hao
17175597088cSDongdong Hao adapter = (struct leapraid_adapter *)shost->hostdata;
17185597088cSDongdong Hao if (shost->nr_hw_queues == 1)
17195597088cSDongdong Hao return;
17205597088cSDongdong Hao
17215597088cSDongdong Hao msix_queue_count = adapter->notification_desc.iopoll_qdex;
17225597088cSDongdong Hao poll_queue_count = adapter->adapter_attr.rq_cnt - msix_queue_count;
17235597088cSDongdong Hao
17245597088cSDongdong Hao queue_offset = 0;
17255597088cSDongdong Hao for (map_index = 0; map_index < shost->nr_maps; map_index++) {
17265597088cSDongdong Hao queue_map = &shost->tag_set.map[map_index];
17275597088cSDongdong Hao queue_map->nr_queues = 0;
17285597088cSDongdong Hao
17295597088cSDongdong Hao switch (map_index) {
17305597088cSDongdong Hao case HCTX_TYPE_DEFAULT:
17315597088cSDongdong Hao queue_map->nr_queues = msix_queue_count;
17325597088cSDongdong Hao queue_map->queue_offset = queue_offset;
17335597088cSDongdong Hao WARN_ON_ONCE(!queue_map->nr_queues);
17345597088cSDongdong Hao blk_mq_map_hw_queues(queue_map,
17355597088cSDongdong Hao &adapter->pdev->dev, 0);
17365597088cSDongdong Hao break;
17375597088cSDongdong Hao case HCTX_TYPE_POLL:
17385597088cSDongdong Hao queue_map->nr_queues = poll_queue_count;
17395597088cSDongdong Hao queue_map->queue_offset = queue_offset;
17405597088cSDongdong Hao blk_mq_map_queues(queue_map);
17415597088cSDongdong Hao break;
17425597088cSDongdong Hao default:
17435597088cSDongdong Hao queue_map->queue_offset = queue_offset;
17445597088cSDongdong Hao blk_mq_map_hw_queues(queue_map,
17455597088cSDongdong Hao &adapter->pdev->dev, 0);
17465597088cSDongdong Hao break;
17475597088cSDongdong Hao }
17485597088cSDongdong Hao queue_offset += queue_map->nr_queues;
17495597088cSDongdong Hao }
17505597088cSDongdong Hao }
17515597088cSDongdong Hao
leapraid_blk_mq_poll(struct Scsi_Host * shost,unsigned int queue_num)17525597088cSDongdong Hao int leapraid_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
17535597088cSDongdong Hao {
17545597088cSDongdong Hao struct leapraid_adapter *adapter =
17555597088cSDongdong Hao (struct leapraid_adapter *)shost->hostdata;
17565597088cSDongdong Hao struct leapraid_blk_mq_poll_rq *blk_mq_poll_rq;
17575597088cSDongdong Hao int num_entries;
17585597088cSDongdong Hao int qid = queue_num - adapter->notification_desc.iopoll_qdex;
17595597088cSDongdong Hao
17605597088cSDongdong Hao blk_mq_poll_rq = &adapter->notification_desc.blk_mq_poll_rqs[qid];
17615597088cSDongdong Hao if (atomic_read(&blk_mq_poll_rq->pause) ||
17625597088cSDongdong Hao !atomic_add_unless(&blk_mq_poll_rq->busy, 1, 1))
17635597088cSDongdong Hao return 0;
17645597088cSDongdong Hao
17655597088cSDongdong Hao num_entries = leapraid_rep_queue_handler(&blk_mq_poll_rq->rq);
17665597088cSDongdong Hao atomic_dec(&blk_mq_poll_rq->busy);
17675597088cSDongdong Hao return num_entries;
17685597088cSDongdong Hao }
17695597088cSDongdong Hao
leapraid_bios_param(struct scsi_device * sdev,struct gendisk * disk,sector_t capacity,int geom[])17705597088cSDongdong Hao static int leapraid_bios_param(struct scsi_device *sdev,
17715597088cSDongdong Hao struct gendisk *disk, sector_t capacity,
17725597088cSDongdong Hao int geom[])
17735597088cSDongdong Hao {
17745597088cSDongdong Hao int heads;
17755597088cSDongdong Hao int sectors;
17765597088cSDongdong Hao sector_t cylinders;
17775597088cSDongdong Hao
17785597088cSDongdong Hao if (scsi_partsize(disk, capacity, geom))
17795597088cSDongdong Hao return 0;
17805597088cSDongdong Hao
17815597088cSDongdong Hao if ((ulong)capacity >= LEAPRAID_LARGE_DISK_THRESHOLD) {
17825597088cSDongdong Hao heads = LEAPRAID_LARGE_DISK_HEADS;
17835597088cSDongdong Hao sectors = LEAPRAID_LARGE_DISK_SECTORS;
17845597088cSDongdong Hao } else {
17855597088cSDongdong Hao heads = LEAPRAID_SMALL_DISK_HEADS;
17865597088cSDongdong Hao sectors = LEAPRAID_SMALL_DISK_SECTORS;
17875597088cSDongdong Hao }
17885597088cSDongdong Hao
17895597088cSDongdong Hao cylinders = capacity;
17905597088cSDongdong Hao sector_div(cylinders, heads * sectors);
17915597088cSDongdong Hao
17925597088cSDongdong Hao geom[0] = heads;
17935597088cSDongdong Hao geom[1] = sectors;
17945597088cSDongdong Hao geom[2] = cylinders;
17955597088cSDongdong Hao return 0;
17965597088cSDongdong Hao }
17975597088cSDongdong Hao
fw_queue_depth_show(struct device * cdev,struct device_attribute * attr,char * buf)17985597088cSDongdong Hao static ssize_t fw_queue_depth_show(struct device *cdev,
17995597088cSDongdong Hao struct device_attribute *attr,
18005597088cSDongdong Hao char *buf)
18015597088cSDongdong Hao {
18025597088cSDongdong Hao struct Scsi_Host *shost = class_to_shost(cdev);
18035597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
18045597088cSDongdong Hao
18055597088cSDongdong Hao return sysfs_emit(buf, "%02d\n",
18065597088cSDongdong Hao adapter->adapter_attr.features.req_slot);
18075597088cSDongdong Hao }
18085597088cSDongdong Hao
host_sas_address_show(struct device * cdev,struct device_attribute * attr,char * buf)18095597088cSDongdong Hao static ssize_t host_sas_address_show(struct device *cdev,
18105597088cSDongdong Hao struct device_attribute *attr, char *buf)
18115597088cSDongdong Hao {
18125597088cSDongdong Hao struct Scsi_Host *shost = class_to_shost(cdev);
18135597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
18145597088cSDongdong Hao
18155597088cSDongdong Hao return sysfs_emit(buf, "0x%016llx\n",
18165597088cSDongdong Hao (unsigned long long)adapter->dev_topo.card.sas_address);
18175597088cSDongdong Hao }
18185597088cSDongdong Hao
board_name_show(struct device * cdev,struct device_attribute * attr,char * buf)18195597088cSDongdong Hao static ssize_t board_name_show(struct device *cdev,
18205597088cSDongdong Hao struct device_attribute *attr, char *buf)
18215597088cSDongdong Hao {
18225597088cSDongdong Hao struct Scsi_Host *shost = class_to_shost(cdev);
18235597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost);
18245597088cSDongdong Hao
18255597088cSDongdong Hao return sysfs_emit(buf, "%s\n", adapter->adapter_attr.board_name);
18265597088cSDongdong Hao }
18275597088cSDongdong Hao
18285597088cSDongdong Hao static DEVICE_ATTR_RO(fw_queue_depth);
18295597088cSDongdong Hao static DEVICE_ATTR_RO(host_sas_address);
18305597088cSDongdong Hao static DEVICE_ATTR_RO(board_name);
18315597088cSDongdong Hao
18325597088cSDongdong Hao static struct attribute *leapraid_shost_attrs[] = {
18335597088cSDongdong Hao &dev_attr_fw_queue_depth.attr,
18345597088cSDongdong Hao &dev_attr_host_sas_address.attr,
18355597088cSDongdong Hao &dev_attr_board_name.attr,
18365597088cSDongdong Hao NULL,
18375597088cSDongdong Hao };
18385597088cSDongdong Hao
18395597088cSDongdong Hao ATTRIBUTE_GROUPS(leapraid_shost);
18405597088cSDongdong Hao
sas_device_handle_show(struct device * dev,struct device_attribute * attr,char * buf)18415597088cSDongdong Hao static ssize_t sas_device_handle_show(struct device *dev,
18425597088cSDongdong Hao struct device_attribute *attr, char *buf)
18435597088cSDongdong Hao {
18445597088cSDongdong Hao struct scsi_device *sdev = to_scsi_device(dev);
18455597088cSDongdong Hao struct leapraid_sdev_priv *sas_device_priv_data = sdev->hostdata;
18465597088cSDongdong Hao
18475597088cSDongdong Hao if (!sas_device_priv_data || !sas_device_priv_data->starget_priv) {
18485597088cSDongdong Hao dev_err(&sdev->sdev_gendev,
18495597088cSDongdong Hao "%s: Invalid sdev_priv or starget_priv\n", __func__);
18505597088cSDongdong Hao return -EINVAL;
18515597088cSDongdong Hao }
18525597088cSDongdong Hao
18535597088cSDongdong Hao return sysfs_emit(buf, "0x%04x\n",
18545597088cSDongdong Hao sas_device_priv_data->starget_priv->hdl);
18555597088cSDongdong Hao }
18565597088cSDongdong Hao
sas_ncq_prio_supported_show(struct device * dev,struct device_attribute * attr,char * buf)1857*46f861d3SDongdong Hao static ssize_t sas_ncq_prio_supported_show(struct device *dev,
1858*46f861d3SDongdong Hao struct device_attribute *attr,
1859*46f861d3SDongdong Hao char *buf)
1860*46f861d3SDongdong Hao {
1861*46f861d3SDongdong Hao struct scsi_device *sdev = to_scsi_device(dev);
1862*46f861d3SDongdong Hao
1863*46f861d3SDongdong Hao return sysfs_emit(buf, "%d\n", sas_ata_ncq_prio_supported(sdev));
1864*46f861d3SDongdong Hao }
1865*46f861d3SDongdong Hao
sas_ncq_prio_enable_show(struct device * dev,struct device_attribute * attr,char * buf)1866*46f861d3SDongdong Hao static ssize_t sas_ncq_prio_enable_show(struct device *dev,
18675597088cSDongdong Hao struct device_attribute *attr,
18685597088cSDongdong Hao char *buf)
18695597088cSDongdong Hao {
18705597088cSDongdong Hao struct scsi_device *sdev = to_scsi_device(dev);
18715597088cSDongdong Hao struct leapraid_sdev_priv *sas_device_priv_data = sdev->hostdata;
18725597088cSDongdong Hao
18735597088cSDongdong Hao if (!sas_device_priv_data) {
18745597088cSDongdong Hao dev_err(&sdev->sdev_gendev,
18755597088cSDongdong Hao "%s: Invalid sdev_priv\n", __func__);
18765597088cSDongdong Hao return -EINVAL;
18775597088cSDongdong Hao }
18785597088cSDongdong Hao
1879*46f861d3SDongdong Hao return sysfs_emit(buf, "%d\n", sas_device_priv_data->ncq_prio_enable);
18805597088cSDongdong Hao }
18815597088cSDongdong Hao
sas_ncq_prio_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1882*46f861d3SDongdong Hao static ssize_t sas_ncq_prio_enable_store(struct device *dev,
18835597088cSDongdong Hao struct device_attribute *attr,
18845597088cSDongdong Hao const char *buf, size_t count)
18855597088cSDongdong Hao {
18865597088cSDongdong Hao struct scsi_device *sdev = to_scsi_device(dev);
18875597088cSDongdong Hao struct leapraid_sdev_priv *sas_device_priv_data = sdev->hostdata;
1888*46f861d3SDongdong Hao bool enable;
18895597088cSDongdong Hao
18905597088cSDongdong Hao if (!sas_device_priv_data) {
18915597088cSDongdong Hao dev_err(&sdev->sdev_gendev,
18925597088cSDongdong Hao "%s: Invalid sdev_priv\n", __func__);
18935597088cSDongdong Hao return -EINVAL;
18945597088cSDongdong Hao }
18955597088cSDongdong Hao
1896*46f861d3SDongdong Hao if (kstrtobool(buf, &enable))
18975597088cSDongdong Hao return -EINVAL;
18985597088cSDongdong Hao
1899*46f861d3SDongdong Hao if (!sas_ata_ncq_prio_supported(sdev))
19005597088cSDongdong Hao return -EINVAL;
19015597088cSDongdong Hao
1902*46f861d3SDongdong Hao sas_device_priv_data->ncq_prio_enable = enable;
19035597088cSDongdong Hao return count;
19045597088cSDongdong Hao }
19055597088cSDongdong Hao
19065597088cSDongdong Hao static DEVICE_ATTR_RO(sas_device_handle);
1907*46f861d3SDongdong Hao static DEVICE_ATTR_RO(sas_ncq_prio_supported);
1908*46f861d3SDongdong Hao static DEVICE_ATTR_RW(sas_ncq_prio_enable);
19095597088cSDongdong Hao
leapraid_sdev_is_sata(struct scsi_device * sdev)1910*46f861d3SDongdong Hao static bool leapraid_sdev_is_sata(struct scsi_device *sdev)
1911*46f861d3SDongdong Hao {
1912*46f861d3SDongdong Hao struct scsi_target *starget = sdev->sdev_target;
1913*46f861d3SDongdong Hao struct leapraid_starget_priv *starget_priv = starget->hostdata;
1914*46f861d3SDongdong Hao struct leapraid_sas_dev *sas_dev;
1915*46f861d3SDongdong Hao
1916*46f861d3SDongdong Hao if (!starget_priv)
1917*46f861d3SDongdong Hao return false;
1918*46f861d3SDongdong Hao
1919*46f861d3SDongdong Hao sas_dev = starget_priv->sas_dev;
1920*46f861d3SDongdong Hao return sas_dev && (sas_dev->dev_info & LEAPRAID_DEVTYP_SATA_DEV);
1921*46f861d3SDongdong Hao }
19225597088cSDongdong Hao
19235597088cSDongdong Hao static struct attribute *leapraid_sdev_attrs[] = {
19245597088cSDongdong Hao &dev_attr_sas_device_handle.attr,
1925*46f861d3SDongdong Hao &dev_attr_sas_ncq_prio_supported.attr,
1926*46f861d3SDongdong Hao &dev_attr_sas_ncq_prio_enable.attr,
19275597088cSDongdong Hao NULL,
19285597088cSDongdong Hao };
19295597088cSDongdong Hao
leapraid_sdev_attr_is_visible(struct kobject * kobj,struct attribute * attr,int i)1930*46f861d3SDongdong Hao static umode_t leapraid_sdev_attr_is_visible(struct kobject *kobj,
1931*46f861d3SDongdong Hao struct attribute *attr, int i)
1932*46f861d3SDongdong Hao {
1933*46f861d3SDongdong Hao struct device *dev = kobj_to_dev(kobj);
1934*46f861d3SDongdong Hao struct scsi_device *sdev = to_scsi_device(dev);
1935*46f861d3SDongdong Hao
1936*46f861d3SDongdong Hao if (attr == &dev_attr_sas_ncq_prio_supported.attr ||
1937*46f861d3SDongdong Hao attr == &dev_attr_sas_ncq_prio_enable.attr)
1938*46f861d3SDongdong Hao if (!leapraid_sdev_is_sata(sdev))
1939*46f861d3SDongdong Hao return 0;
1940*46f861d3SDongdong Hao
1941*46f861d3SDongdong Hao return attr->mode;
1942*46f861d3SDongdong Hao }
1943*46f861d3SDongdong Hao
1944*46f861d3SDongdong Hao static const struct attribute_group leapraid_sdev_attr_group = {
1945*46f861d3SDongdong Hao .attrs = leapraid_sdev_attrs,
1946*46f861d3SDongdong Hao .is_visible = leapraid_sdev_attr_is_visible,
1947*46f861d3SDongdong Hao };
1948*46f861d3SDongdong Hao
1949*46f861d3SDongdong Hao static const struct attribute_group *leapraid_sdev_groups[] = {
1950*46f861d3SDongdong Hao &leapraid_sdev_attr_group,
1951*46f861d3SDongdong Hao NULL,
1952*46f861d3SDongdong Hao };
19535597088cSDongdong Hao
19545597088cSDongdong Hao static struct scsi_host_template leapraid_driver_template = {
19555597088cSDongdong Hao .module = THIS_MODULE,
19565597088cSDongdong Hao .name = "LEAPIO RAID Host",
19575597088cSDongdong Hao .proc_name = LEAPRAID_DRIVER_NAME,
19585597088cSDongdong Hao .queuecommand = leapraid_queuecommand,
19595597088cSDongdong Hao .cmd_size = sizeof(struct leapraid_io_req_tracker),
19605597088cSDongdong Hao .init_cmd_priv = leapraid_init_cmd_priv,
19615597088cSDongdong Hao .exit_cmd_priv = leapraid_exit_cmd_priv,
19625597088cSDongdong Hao .eh_abort_handler = leapraid_eh_abort_handler,
19635597088cSDongdong Hao .eh_device_reset_handler = leapraid_eh_device_reset_handler,
19645597088cSDongdong Hao .eh_target_reset_handler = leapraid_eh_target_reset_handler,
19655597088cSDongdong Hao .eh_host_reset_handler = leapraid_eh_host_reset_handler,
19665597088cSDongdong Hao .sdev_init = leapraid_sdev_init,
19675597088cSDongdong Hao .sdev_destroy = leapraid_sdev_destroy,
19685597088cSDongdong Hao .sdev_configure = leapraid_sdev_configure,
19695597088cSDongdong Hao .target_alloc = leapraid_target_alloc,
19705597088cSDongdong Hao .target_destroy = leapraid_target_destroy,
19715597088cSDongdong Hao .scan_finished = leapraid_scan_finished,
19725597088cSDongdong Hao .scan_start = leapraid_scan_start,
19735597088cSDongdong Hao .change_queue_depth = leapraid_change_queue_depth,
19745597088cSDongdong Hao .map_queues = leapraid_map_queues,
19755597088cSDongdong Hao .mq_poll = leapraid_blk_mq_poll,
19765597088cSDongdong Hao .bios_param = leapraid_bios_param,
19775597088cSDongdong Hao .can_queue = LEAPRAID_CAN_QUEUE_MIN,
19785597088cSDongdong Hao .this_id = LEAPRAID_THIS_ID_NONE,
19795597088cSDongdong Hao .sg_tablesize = LEAPRAID_SG_DEPTH,
19805597088cSDongdong Hao .max_sectors = LEAPRAID_MAX_SECTORS,
19815597088cSDongdong Hao .max_segment_size = LEAPRAID_MAX_SEGMENT_SIZE,
19825597088cSDongdong Hao .cmd_per_lun = LEAPRAID_CMD_PER_LUN,
19835597088cSDongdong Hao .shost_groups = leapraid_shost_groups,
19845597088cSDongdong Hao .sdev_groups = leapraid_sdev_groups,
19855597088cSDongdong Hao .track_queue_depth = 1,
19865597088cSDongdong Hao };
19875597088cSDongdong Hao
leapraid_lock_init(struct leapraid_adapter * adapter)19885597088cSDongdong Hao static void leapraid_lock_init(struct leapraid_adapter *adapter)
19895597088cSDongdong Hao {
19905597088cSDongdong Hao mutex_init(&adapter->reset_desc.adapter_reset_mutex);
19915597088cSDongdong Hao mutex_init(&adapter->reset_desc.host_diag_mutex);
19925597088cSDongdong Hao mutex_init(&adapter->access_ctrl.pci_access_lock);
19935597088cSDongdong Hao
19945597088cSDongdong Hao spin_lock_init(&adapter->reset_desc.adapter_reset_lock);
19955597088cSDongdong Hao spin_lock_init(&adapter->dynamic_task_desc.task_lock);
19965597088cSDongdong Hao spin_lock_init(&adapter->dev_topo.sas_dev_lock);
19975597088cSDongdong Hao spin_lock_init(&adapter->dev_topo.topo_node_lock);
19985597088cSDongdong Hao spin_lock_init(&adapter->fw_evt_s.fw_evt_lock);
19995597088cSDongdong Hao spin_lock_init(&adapter->dev_topo.raid_volume_lock);
20005597088cSDongdong Hao spin_lock_init(&adapter->dev_topo.enc_lock);
20015597088cSDongdong Hao spin_lock_init(&adapter->boot_devs.lock);
20025597088cSDongdong Hao }
20035597088cSDongdong Hao
leapraid_list_init(struct leapraid_adapter * adapter)20045597088cSDongdong Hao static void leapraid_list_init(struct leapraid_adapter *adapter)
20055597088cSDongdong Hao {
20065597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.sas_dev_list);
20075597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.card_port_list);
20085597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.sas_dev_init_list);
20095597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.exp_list);
20105597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.enc_list);
20115597088cSDongdong Hao INIT_LIST_HEAD(&adapter->fw_evt_s.fw_evt_list);
20125597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.raid_volume_list);
20135597088cSDongdong Hao INIT_LIST_HEAD(&adapter->dev_topo.card.sas_port_list);
20145597088cSDongdong Hao }
20155597088cSDongdong Hao
leapraid_probe(struct pci_dev * pdev,const struct pci_device_id * id)20165597088cSDongdong Hao static int leapraid_probe(struct pci_dev *pdev, const struct pci_device_id *id)
20175597088cSDongdong Hao {
20185597088cSDongdong Hao struct leapraid_adapter *adapter;
20195597088cSDongdong Hao struct Scsi_Host *shost;
20205597088cSDongdong Hao int iopoll_q_count;
20215597088cSDongdong Hao int rc;
20225597088cSDongdong Hao
20235597088cSDongdong Hao shost = scsi_host_alloc(&leapraid_driver_template,
20245597088cSDongdong Hao sizeof(struct leapraid_adapter));
20255597088cSDongdong Hao if (!shost) {
20265597088cSDongdong Hao dev_err(&pdev->dev,
20275597088cSDongdong Hao "%s: SCSI host alloc failed\n", __func__);
20285597088cSDongdong Hao return -ENODEV;
20295597088cSDongdong Hao }
20305597088cSDongdong Hao
20315597088cSDongdong Hao adapter = shost_priv(shost);
20325597088cSDongdong Hao memset(adapter, 0, sizeof(struct leapraid_adapter));
20335597088cSDongdong Hao
20345597088cSDongdong Hao init_waitqueue_head(&adapter->access_ctrl.recovery_waitq);
20355597088cSDongdong Hao adapter->adapter_attr.id = atomic_inc_return(&leapraid_ids) - 1;
20365597088cSDongdong Hao
20375597088cSDongdong Hao adapter->adapter_attr.enable_mp = enable_mp;
20385597088cSDongdong Hao
20395597088cSDongdong Hao adapter = shost_priv(shost);
20405597088cSDongdong Hao INIT_LIST_HEAD(&adapter->list);
20415597088cSDongdong Hao
20425597088cSDongdong Hao adapter->shost = shost;
20435597088cSDongdong Hao adapter->pdev = pdev;
20445597088cSDongdong Hao adapter->fw_log_desc.open_pcie_trace = open_pcie_trace;
20455597088cSDongdong Hao atomic_set(&adapter->fw_log_desc.mmap_refcnt, 0);
20465597088cSDongdong Hao init_waitqueue_head(&adapter->fw_log_desc.mmap_waitq);
20475597088cSDongdong Hao leapraid_lock_init(adapter);
20485597088cSDongdong Hao leapraid_list_init(adapter);
20495597088cSDongdong Hao snprintf(adapter->adapter_attr.name, LEAPRAID_NAME_LENGTH, "%s%d",
20505597088cSDongdong Hao LEAPRAID_DRIVER_NAME, adapter->adapter_attr.id);
20515597088cSDongdong Hao
20525597088cSDongdong Hao shost->max_cmd_len = LEAPRAID_MAX_CDB_LEN;
20535597088cSDongdong Hao shost->max_lun = LEAPRAID_MAX_LUNS;
20545597088cSDongdong Hao shost->transportt = leapraid_transport_template;
20555597088cSDongdong Hao shost->unique_id = adapter->adapter_attr.id;
20565597088cSDongdong Hao
20575597088cSDongdong Hao snprintf(adapter->fw_evt_s.fw_evt_name,
20585597088cSDongdong Hao sizeof(adapter->fw_evt_s.fw_evt_name),
20595597088cSDongdong Hao "fw_event_%s%d", LEAPRAID_DRIVER_NAME,
20605597088cSDongdong Hao adapter->adapter_attr.id);
20615597088cSDongdong Hao adapter->fw_evt_s.fw_evt_thread =
20625597088cSDongdong Hao alloc_ordered_workqueue(adapter->fw_evt_s.fw_evt_name, 0);
20635597088cSDongdong Hao if (!adapter->fw_evt_s.fw_evt_thread) {
20645597088cSDongdong Hao dev_err(&adapter->pdev->dev,
20655597088cSDongdong Hao "%s: Failed to create fw event workqueue\n", __func__);
20665597088cSDongdong Hao rc = -ENODEV;
20675597088cSDongdong Hao goto evt_wq_fail;
20685597088cSDongdong Hao }
20695597088cSDongdong Hao
20705597088cSDongdong Hao shost->host_tagset = 1;
20715597088cSDongdong Hao init_waitqueue_head(&adapter->scan_dev_desc.wait_driver_loading);
20725597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 1;
20735597088cSDongdong Hao if (leapraid_ctrl_init(adapter)) {
20745597088cSDongdong Hao dev_err(&adapter->pdev->dev,
20755597088cSDongdong Hao "%s: Adapter init failed\n", __func__);
20765597088cSDongdong Hao rc = -ENODEV;
20775597088cSDongdong Hao goto ctrl_init_fail;
20785597088cSDongdong Hao }
20795597088cSDongdong Hao
20805597088cSDongdong Hao shost->nr_hw_queues = 1;
20815597088cSDongdong Hao if (shost->host_tagset) {
20825597088cSDongdong Hao shost->nr_hw_queues = adapter->adapter_attr.rq_cnt;
20835597088cSDongdong Hao iopoll_q_count = adapter->adapter_attr.rq_cnt -
20845597088cSDongdong Hao adapter->notification_desc.iopoll_qdex;
20855597088cSDongdong Hao shost->nr_maps = iopoll_q_count ? 3 : 1;
20865597088cSDongdong Hao dev_info(&adapter->pdev->dev,
20875597088cSDongdong Hao "Max scsi I/O cmds %d shared with nr_hw_queues=%d\n",
20885597088cSDongdong Hao shost->can_queue, shost->nr_hw_queues);
20895597088cSDongdong Hao }
20905597088cSDongdong Hao
20915597088cSDongdong Hao rc = scsi_add_host(shost, &pdev->dev);
20925597088cSDongdong Hao if (rc) {
20935597088cSDongdong Hao dev_err(&pdev->dev,
20945597088cSDongdong Hao "%s: SCSI host add failed\n", __func__);
20955597088cSDongdong Hao goto scsi_add_shost_fail;
20965597088cSDongdong Hao }
20975597088cSDongdong Hao
20985597088cSDongdong Hao spin_lock(&leapraid_adapter_lock);
20995597088cSDongdong Hao list_add_tail(&adapter->list, &leapraid_adapter_list);
21005597088cSDongdong Hao spin_unlock(&leapraid_adapter_lock);
21015597088cSDongdong Hao
21025597088cSDongdong Hao scsi_scan_host(shost);
21035597088cSDongdong Hao return 0;
21045597088cSDongdong Hao
21055597088cSDongdong Hao scsi_add_shost_fail:
21065597088cSDongdong Hao leapraid_remove_ctrl(adapter);
21075597088cSDongdong Hao ctrl_init_fail:
21085597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
21095597088cSDongdong Hao destroy_workqueue(adapter->fw_evt_s.fw_evt_thread);
21105597088cSDongdong Hao evt_wq_fail:
21115597088cSDongdong Hao scsi_host_put(shost);
21125597088cSDongdong Hao return rc;
21135597088cSDongdong Hao }
21145597088cSDongdong Hao
leapraid_cleanup_lists(struct leapraid_adapter * adapter)21155597088cSDongdong Hao void leapraid_cleanup_lists(struct leapraid_adapter *adapter)
21165597088cSDongdong Hao {
21175597088cSDongdong Hao struct leapraid_raid_volume *raid_volume, *next_raid_volume;
21185597088cSDongdong Hao struct leapraid_starget_priv *starget_priv_data;
21195597088cSDongdong Hao struct leapraid_sas_port *leapraid_port, *next_port;
21205597088cSDongdong Hao struct leapraid_card_port *port, *port_next;
21215597088cSDongdong Hao struct leapraid_vphy *vphy, *vphy_next;
21225597088cSDongdong Hao
21235597088cSDongdong Hao list_for_each_entry_safe(raid_volume, next_raid_volume,
21245597088cSDongdong Hao &adapter->dev_topo.raid_volume_list, list) {
21255597088cSDongdong Hao if (raid_volume->starget) {
21265597088cSDongdong Hao starget_priv_data = raid_volume->starget->hostdata;
21275597088cSDongdong Hao if (starget_priv_data)
21285597088cSDongdong Hao starget_priv_data->deleted = 1;
21295597088cSDongdong Hao scsi_remove_target(&raid_volume->starget->dev);
21305597088cSDongdong Hao }
21315597088cSDongdong Hao dev_info(&adapter->pdev->dev,
21325597088cSDongdong Hao "removing hdl=0x%04x, wwid=0x%016llx\n",
21335597088cSDongdong Hao raid_volume->hdl,
21345597088cSDongdong Hao (unsigned long long)raid_volume->wwid);
21355597088cSDongdong Hao leapraid_raid_volume_remove(adapter, raid_volume);
21365597088cSDongdong Hao }
21375597088cSDongdong Hao
21385597088cSDongdong Hao list_for_each_entry_safe(leapraid_port, next_port,
21395597088cSDongdong Hao &adapter->dev_topo.card.sas_port_list,
21405597088cSDongdong Hao port_list) {
21415597088cSDongdong Hao if (leapraid_port->remote_identify.device_type ==
21425597088cSDongdong Hao SAS_END_DEVICE)
21435597088cSDongdong Hao leapraid_sas_dev_remove_by_sas_address(
21445597088cSDongdong Hao adapter,
21455597088cSDongdong Hao leapraid_port->remote_identify.sas_address,
21465597088cSDongdong Hao leapraid_port->card_port);
21475597088cSDongdong Hao else if (leapraid_port->remote_identify.device_type ==
21485597088cSDongdong Hao SAS_EDGE_EXPANDER_DEVICE ||
21495597088cSDongdong Hao leapraid_port->remote_identify.device_type ==
21505597088cSDongdong Hao SAS_FANOUT_EXPANDER_DEVICE)
21515597088cSDongdong Hao leapraid_exp_rm(
21525597088cSDongdong Hao adapter,
21535597088cSDongdong Hao leapraid_port->remote_identify.sas_address,
21545597088cSDongdong Hao leapraid_port->card_port);
21555597088cSDongdong Hao }
21565597088cSDongdong Hao
21575597088cSDongdong Hao list_for_each_entry_safe(port, port_next,
21585597088cSDongdong Hao &adapter->dev_topo.card_port_list, list) {
21595597088cSDongdong Hao if (port->vphys_mask)
21605597088cSDongdong Hao list_for_each_entry_safe(vphy, vphy_next,
21615597088cSDongdong Hao &port->vphys_list, list) {
21625597088cSDongdong Hao list_del(&vphy->list);
21635597088cSDongdong Hao kfree(vphy);
21645597088cSDongdong Hao }
21655597088cSDongdong Hao list_del(&port->list);
21665597088cSDongdong Hao kfree(port);
21675597088cSDongdong Hao }
21685597088cSDongdong Hao
21695597088cSDongdong Hao if (adapter->dev_topo.card.phys_num) {
21705597088cSDongdong Hao kfree(adapter->dev_topo.card.card_phy);
21715597088cSDongdong Hao adapter->dev_topo.card.card_phy = NULL;
21725597088cSDongdong Hao adapter->dev_topo.card.phys_num = 0;
21735597088cSDongdong Hao }
21745597088cSDongdong Hao }
21755597088cSDongdong Hao
leapraid_remove(struct pci_dev * pdev)21765597088cSDongdong Hao static void leapraid_remove(struct pci_dev *pdev)
21775597088cSDongdong Hao {
21785597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
21795597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
21805597088cSDongdong Hao struct workqueue_struct *wq;
21815597088cSDongdong Hao unsigned long flags;
21825597088cSDongdong Hao
21835597088cSDongdong Hao if (!shost || !adapter) {
21845597088cSDongdong Hao dev_err(&pdev->dev, "Unable to remove!\n");
21855597088cSDongdong Hao return;
21865597088cSDongdong Hao }
21875597088cSDongdong Hao
21885597088cSDongdong Hao wait_event(adapter->scan_dev_desc.wait_driver_loading,
21895597088cSDongdong Hao !adapter->scan_dev_desc.driver_loading);
21905597088cSDongdong Hao wait_event(adapter->scan_dev_desc.wait_driver_loading,
21915597088cSDongdong Hao !atomic_read(&adapter->overheat_desc.thermal_alert));
21925597088cSDongdong Hao
21935597088cSDongdong Hao WRITE_ONCE(adapter->access_ctrl.host_removing, 1);
21945597088cSDongdong Hao spin_lock(&leapraid_adapter_lock);
21955597088cSDongdong Hao list_del(&adapter->list);
21965597088cSDongdong Hao spin_unlock(&leapraid_adapter_lock);
21975597088cSDongdong Hao
21985597088cSDongdong Hao leapraid_wait_cmds_done(adapter);
21995597088cSDongdong Hao
22005597088cSDongdong Hao if (leapraid_pci_removed(adapter)) {
22015597088cSDongdong Hao leapraid_mq_polling_pause(adapter);
22025597088cSDongdong Hao leapraid_clean_active_scsi_cmds(adapter);
22035597088cSDongdong Hao }
22045597088cSDongdong Hao leapraid_clean_active_fw_evt(adapter);
22055597088cSDongdong Hao
22065597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
22075597088cSDongdong Hao wq = adapter->fw_evt_s.fw_evt_thread;
22085597088cSDongdong Hao adapter->fw_evt_s.fw_evt_thread = NULL;
22095597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
22105597088cSDongdong Hao if (wq)
22115597088cSDongdong Hao destroy_workqueue(wq);
22125597088cSDongdong Hao
22135597088cSDongdong Hao sas_remove_host(shost);
22145597088cSDongdong Hao leapraid_cleanup_lists(adapter);
22155597088cSDongdong Hao leapraid_remove_ctrl(adapter);
22165597088cSDongdong Hao scsi_host_put(shost);
22175597088cSDongdong Hao }
22185597088cSDongdong Hao
leapraid_shutdown(struct pci_dev * pdev)22195597088cSDongdong Hao static void leapraid_shutdown(struct pci_dev *pdev)
22205597088cSDongdong Hao {
22215597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
22225597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
22235597088cSDongdong Hao struct workqueue_struct *wq;
22245597088cSDongdong Hao unsigned long flags;
22255597088cSDongdong Hao
22265597088cSDongdong Hao if (!shost || !adapter) {
22275597088cSDongdong Hao dev_err(&pdev->dev, "Unable to shutdown!\n");
22285597088cSDongdong Hao return;
22295597088cSDongdong Hao }
22305597088cSDongdong Hao
22315597088cSDongdong Hao adapter->access_ctrl.host_removing = 1;
22325597088cSDongdong Hao leapraid_wait_cmds_done(adapter);
22335597088cSDongdong Hao leapraid_clean_active_fw_evt(adapter);
22345597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
22355597088cSDongdong Hao leapraid_fw_log_stop(adapter);
22365597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
22375597088cSDongdong Hao wq = adapter->fw_evt_s.fw_evt_thread;
22385597088cSDongdong Hao adapter->fw_evt_s.fw_evt_thread = NULL;
22395597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
22405597088cSDongdong Hao if (wq)
22415597088cSDongdong Hao destroy_workqueue(wq);
22425597088cSDongdong Hao
22435597088cSDongdong Hao leapraid_disable_controller(adapter);
22445597088cSDongdong Hao }
22455597088cSDongdong Hao
leapraid_pci_error_detected(struct pci_dev * pdev,pci_channel_state_t state)22465597088cSDongdong Hao static pci_ers_result_t leapraid_pci_error_detected(struct pci_dev *pdev,
22475597088cSDongdong Hao pci_channel_state_t state)
22485597088cSDongdong Hao {
22495597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
22505597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
22515597088cSDongdong Hao
22525597088cSDongdong Hao if (!shost || !adapter) {
22535597088cSDongdong Hao dev_err(&pdev->dev, "Failed to error detected for device\n");
22545597088cSDongdong Hao return PCI_ERS_RESULT_DISCONNECT;
22555597088cSDongdong Hao }
22565597088cSDongdong Hao
22575597088cSDongdong Hao dev_err(&pdev->dev, "%s: PCI error detected, state=%d\n",
22585597088cSDongdong Hao adapter->adapter_attr.name, state);
22595597088cSDongdong Hao
22605597088cSDongdong Hao switch (state) {
22615597088cSDongdong Hao case pci_channel_io_normal:
22625597088cSDongdong Hao return PCI_ERS_RESULT_CAN_RECOVER;
22635597088cSDongdong Hao case pci_channel_io_frozen:
22645597088cSDongdong Hao adapter->access_ctrl.pcie_recovering = 1;
22655597088cSDongdong Hao scsi_block_requests(adapter->shost);
22665597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
22675597088cSDongdong Hao leapraid_check_scheduled_fault_stop(adapter);
22685597088cSDongdong Hao leapraid_fw_log_stop(adapter);
22695597088cSDongdong Hao leapraid_disable_controller(adapter);
22705597088cSDongdong Hao return PCI_ERS_RESULT_NEED_RESET;
22715597088cSDongdong Hao case pci_channel_io_perm_failure:
22725597088cSDongdong Hao adapter->access_ctrl.pcie_recovering = 1;
22735597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
22745597088cSDongdong Hao leapraid_check_scheduled_fault_stop(adapter);
22755597088cSDongdong Hao leapraid_fw_log_stop(adapter);
22765597088cSDongdong Hao leapraid_mq_polling_pause(adapter);
22775597088cSDongdong Hao leapraid_clean_active_scsi_cmds(adapter);
22785597088cSDongdong Hao return PCI_ERS_RESULT_DISCONNECT;
22795597088cSDongdong Hao }
22805597088cSDongdong Hao
22815597088cSDongdong Hao return PCI_ERS_RESULT_NEED_RESET;
22825597088cSDongdong Hao }
22835597088cSDongdong Hao
leapraid_pci_mmio_enabled(struct pci_dev * pdev)22845597088cSDongdong Hao static pci_ers_result_t leapraid_pci_mmio_enabled(struct pci_dev *pdev)
22855597088cSDongdong Hao {
22865597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
22875597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
22885597088cSDongdong Hao
22895597088cSDongdong Hao if (!shost || !adapter) {
22905597088cSDongdong Hao dev_err(&pdev->dev,
22915597088cSDongdong Hao "Failed to enable mmio for device\n");
22925597088cSDongdong Hao return PCI_ERS_RESULT_DISCONNECT;
22935597088cSDongdong Hao }
22945597088cSDongdong Hao
22955597088cSDongdong Hao dev_info(&pdev->dev, "%s: PCI error mmio enabled\n",
22965597088cSDongdong Hao adapter->adapter_attr.name);
22975597088cSDongdong Hao
22985597088cSDongdong Hao return PCI_ERS_RESULT_RECOVERED;
22995597088cSDongdong Hao }
23005597088cSDongdong Hao
leapraid_pci_slot_reset(struct pci_dev * pdev)23015597088cSDongdong Hao static pci_ers_result_t leapraid_pci_slot_reset(struct pci_dev *pdev)
23025597088cSDongdong Hao {
23035597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
23045597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
23055597088cSDongdong Hao int rc;
23065597088cSDongdong Hao
23075597088cSDongdong Hao if (!shost || !adapter) {
23085597088cSDongdong Hao dev_err(&pdev->dev,
23095597088cSDongdong Hao "Failed to slot reset for device\n");
23105597088cSDongdong Hao return PCI_ERS_RESULT_DISCONNECT;
23115597088cSDongdong Hao }
23125597088cSDongdong Hao
23135597088cSDongdong Hao dev_err(&pdev->dev, "%s PCI error slot reset\n",
23145597088cSDongdong Hao adapter->adapter_attr.name);
23155597088cSDongdong Hao
23165597088cSDongdong Hao adapter->pdev = pdev;
23175597088cSDongdong Hao pci_restore_state(pdev);
23185597088cSDongdong Hao if (leapraid_set_pcie_and_notification(adapter)) {
23195597088cSDongdong Hao dev_err(&pdev->dev,
23205597088cSDongdong Hao "%s: Failed to set PCIe state and notification\n",
23215597088cSDongdong Hao __func__);
23225597088cSDongdong Hao return PCI_ERS_RESULT_DISCONNECT;
23235597088cSDongdong Hao }
23245597088cSDongdong Hao
23255597088cSDongdong Hao adapter->access_ctrl.pcie_recovering = 0;
23265597088cSDongdong Hao dev_info(&pdev->dev, "%s: Hard reset triggered by PCI slot reset\n",
23275597088cSDongdong Hao adapter->adapter_attr.name);
23285597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s: %d: call hard_reset\n",
23295597088cSDongdong Hao __func__, __LINE__);
23305597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
23315597088cSDongdong Hao if (rc)
23325597088cSDongdong Hao dev_err(&pdev->dev, "%s hard reset: failed\n",
23335597088cSDongdong Hao adapter->adapter_attr.name);
23345597088cSDongdong Hao
23355597088cSDongdong Hao return rc == 0 ? PCI_ERS_RESULT_RECOVERED :
23365597088cSDongdong Hao PCI_ERS_RESULT_DISCONNECT;
23375597088cSDongdong Hao }
23385597088cSDongdong Hao
leapraid_pci_resume(struct pci_dev * pdev)23395597088cSDongdong Hao static void leapraid_pci_resume(struct pci_dev *pdev)
23405597088cSDongdong Hao {
23415597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
23425597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
23435597088cSDongdong Hao
23445597088cSDongdong Hao if (!shost || !adapter) {
23455597088cSDongdong Hao dev_err(&pdev->dev, "Failed to resume\n");
23465597088cSDongdong Hao return;
23475597088cSDongdong Hao }
23485597088cSDongdong Hao
23495597088cSDongdong Hao dev_err(&pdev->dev, "PCI error resume!\n");
23505597088cSDongdong Hao
23515597088cSDongdong Hao pci_aer_clear_nonfatal_status(pdev);
23525597088cSDongdong Hao leapraid_check_scheduled_fault_start(adapter);
23535597088cSDongdong Hao leapraid_fw_log_start(adapter);
23545597088cSDongdong Hao scsi_unblock_requests(adapter->shost);
23555597088cSDongdong Hao }
23565597088cSDongdong Hao
23575597088cSDongdong Hao MODULE_DEVICE_TABLE(pci, leapraid_pci_table);
23585597088cSDongdong Hao static struct pci_error_handlers leapraid_err_handler = {
23595597088cSDongdong Hao .error_detected = leapraid_pci_error_detected,
23605597088cSDongdong Hao .mmio_enabled = leapraid_pci_mmio_enabled,
23615597088cSDongdong Hao .slot_reset = leapraid_pci_slot_reset,
23625597088cSDongdong Hao .resume = leapraid_pci_resume,
23635597088cSDongdong Hao };
23645597088cSDongdong Hao
23655597088cSDongdong Hao #ifdef CONFIG_PM
leapraid_suspend(struct pci_dev * pdev,pm_message_t state)23665597088cSDongdong Hao static int leapraid_suspend(struct pci_dev *pdev, pm_message_t state)
23675597088cSDongdong Hao {
23685597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
23695597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
23705597088cSDongdong Hao pci_power_t device_state;
23715597088cSDongdong Hao
23725597088cSDongdong Hao if (!shost || !adapter) {
23735597088cSDongdong Hao dev_err(&pdev->dev,
23745597088cSDongdong Hao "Suspend failed, invalid host or adapter\n");
23755597088cSDongdong Hao return -ENXIO;
23765597088cSDongdong Hao }
23775597088cSDongdong Hao
23785597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
23795597088cSDongdong Hao leapraid_check_scheduled_fault_stop(adapter);
23805597088cSDongdong Hao leapraid_fw_log_stop(adapter);
23815597088cSDongdong Hao scsi_block_requests(shost);
23825597088cSDongdong Hao device_state = pci_choose_state(pdev, state);
23835597088cSDongdong Hao
23845597088cSDongdong Hao dev_info(&pdev->dev, "Entering PCI power state D%d, (slot=%s)\n",
23855597088cSDongdong Hao device_state, pci_name(pdev));
23865597088cSDongdong Hao
23875597088cSDongdong Hao pci_save_state(pdev);
23885597088cSDongdong Hao leapraid_disable_controller(adapter);
23895597088cSDongdong Hao pci_set_power_state(pdev, device_state);
23905597088cSDongdong Hao return 0;
23915597088cSDongdong Hao }
23925597088cSDongdong Hao
leapraid_resume(struct pci_dev * pdev)23935597088cSDongdong Hao static int leapraid_resume(struct pci_dev *pdev)
23945597088cSDongdong Hao {
23955597088cSDongdong Hao struct leapraid_adapter *adapter = pdev_to_adapter(pdev);
23965597088cSDongdong Hao struct Scsi_Host *shost = pci_get_drvdata(pdev);
23975597088cSDongdong Hao pci_power_t device_state = pdev->current_state;
23985597088cSDongdong Hao int rc;
23995597088cSDongdong Hao
24005597088cSDongdong Hao if (!shost || !adapter) {
24015597088cSDongdong Hao dev_err(&pdev->dev,
24025597088cSDongdong Hao "Resume failed, invalid host or adapter\n");
24035597088cSDongdong Hao return -ENXIO;
24045597088cSDongdong Hao }
24055597088cSDongdong Hao
24065597088cSDongdong Hao dev_info(&pdev->dev,
24075597088cSDongdong Hao "Resuming device %s, previous state D%d\n",
24085597088cSDongdong Hao pci_name(pdev), device_state);
24095597088cSDongdong Hao
24105597088cSDongdong Hao pci_set_power_state(pdev, PCI_D0);
24115597088cSDongdong Hao pci_enable_wake(pdev, PCI_D0, 0);
24125597088cSDongdong Hao pci_restore_state(pdev);
24135597088cSDongdong Hao adapter->pdev = pdev;
24145597088cSDongdong Hao rc = leapraid_set_pcie_and_notification(adapter);
24155597088cSDongdong Hao if (rc) {
24165597088cSDongdong Hao dev_err(&pdev->dev,
24175597088cSDongdong Hao "%s: Failed to set PCIe state and notification\n",
24185597088cSDongdong Hao __func__);
24195597088cSDongdong Hao return rc;
24205597088cSDongdong Hao }
24215597088cSDongdong Hao
24225597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
24235597088cSDongdong Hao __func__, __LINE__);
24245597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, PART_RESET);
24255597088cSDongdong Hao if (rc) {
24265597088cSDongdong Hao dev_err(&adapter->pdev->dev,
24275597088cSDongdong Hao "%s: Hard reset failed during resume, rc=%d\n",
24285597088cSDongdong Hao __func__, rc);
24295597088cSDongdong Hao return rc;
24305597088cSDongdong Hao }
24315597088cSDongdong Hao scsi_unblock_requests(shost);
24325597088cSDongdong Hao leapraid_check_scheduled_fault_start(adapter);
24335597088cSDongdong Hao leapraid_fw_log_start(adapter);
24345597088cSDongdong Hao return 0;
24355597088cSDongdong Hao }
24365597088cSDongdong Hao #endif /* CONFIG_PM */
24375597088cSDongdong Hao
24385597088cSDongdong Hao static struct pci_driver leapraid_driver = {
24395597088cSDongdong Hao .name = LEAPRAID_DRIVER_NAME,
24405597088cSDongdong Hao .id_table = leapraid_pci_table,
24415597088cSDongdong Hao .probe = leapraid_probe,
24425597088cSDongdong Hao .remove = leapraid_remove,
24435597088cSDongdong Hao .shutdown = leapraid_shutdown,
24445597088cSDongdong Hao .err_handler = &leapraid_err_handler,
24455597088cSDongdong Hao #ifdef CONFIG_PM
24465597088cSDongdong Hao .suspend = leapraid_suspend,
24475597088cSDongdong Hao .resume = leapraid_resume,
24485597088cSDongdong Hao #endif /* CONFIG_PM */
24495597088cSDongdong Hao };
24505597088cSDongdong Hao
leapraid_init(void)24515597088cSDongdong Hao static int __init leapraid_init(void)
24525597088cSDongdong Hao {
24535597088cSDongdong Hao int error;
24545597088cSDongdong Hao
24555597088cSDongdong Hao pr_info("%s initializing\n", LEAPRAID_DRIVER_NAME);
24565597088cSDongdong Hao
24575597088cSDongdong Hao leapraid_transport_template =
24585597088cSDongdong Hao sas_attach_transport(&leapraid_transport_functions);
24595597088cSDongdong Hao if (!leapraid_transport_template) {
24605597088cSDongdong Hao pr_err("%s: Failed to attach SAS transport\n",
24615597088cSDongdong Hao LEAPRAID_DRIVER_NAME);
24625597088cSDongdong Hao return -ENODEV;
24635597088cSDongdong Hao }
24645597088cSDongdong Hao
24655597088cSDongdong Hao error = pci_register_driver(&leapraid_driver);
24665597088cSDongdong Hao if (error) {
24675597088cSDongdong Hao pr_err("%s: PCI driver registration failed: %d\n",
24685597088cSDongdong Hao LEAPRAID_DRIVER_NAME, error);
24695597088cSDongdong Hao sas_release_transport(leapraid_transport_template);
24705597088cSDongdong Hao return error;
24715597088cSDongdong Hao }
24725597088cSDongdong Hao
24735597088cSDongdong Hao error = leapraid_ctl_init();
24745597088cSDongdong Hao if (error) {
24755597088cSDongdong Hao pci_unregister_driver(&leapraid_driver);
24765597088cSDongdong Hao sas_release_transport(leapraid_transport_template);
24775597088cSDongdong Hao return error;
24785597088cSDongdong Hao }
24795597088cSDongdong Hao
24805597088cSDongdong Hao return 0;
24815597088cSDongdong Hao }
24825597088cSDongdong Hao
leapraid_exit(void)24835597088cSDongdong Hao static void __exit leapraid_exit(void)
24845597088cSDongdong Hao {
24855597088cSDongdong Hao pr_info("%s exiting\n", LEAPRAID_DRIVER_NAME);
24865597088cSDongdong Hao
24875597088cSDongdong Hao leapraid_ctl_exit();
24885597088cSDongdong Hao pci_unregister_driver(&leapraid_driver);
24895597088cSDongdong Hao sas_release_transport(leapraid_transport_template);
24905597088cSDongdong Hao }
24915597088cSDongdong Hao
24925597088cSDongdong Hao module_init(leapraid_init);
24935597088cSDongdong Hao module_exit(leapraid_exit);
2494