diff options
author | Sarang Radke <sarang.radke@qlogic.com> | 2010-03-19 20:03:59 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-04-11 10:45:50 -0400 |
commit | 09ff701a177b116c6c15b6e501e58fbfb306b424 (patch) | |
tree | fd99933ea29dbc36fc6636f5278d237dbee89b96 /drivers/scsi/qla2xxx/qla_bsg.c | |
parent | 6e98016ca077c5c751167bfdb1a3a2a3bee581cf (diff) |
[SCSI] qla2xxx: Add APEX support.
Allows priority setting for FCP_CMNDs.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_bsg.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index c20292fde720..3c3a86ca6cbd 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c | |||
@@ -35,6 +35,166 @@ done: | |||
35 | return sp; | 35 | return sp; |
36 | } | 36 | } |
37 | 37 | ||
38 | int | ||
39 | qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) | ||
40 | { | ||
41 | int i, ret, num_valid; | ||
42 | uint8_t *bcode; | ||
43 | struct qla_fcp_prio_entry *pri_entry; | ||
44 | |||
45 | ret = 1; | ||
46 | num_valid = 0; | ||
47 | bcode = (uint8_t *)pri_cfg; | ||
48 | |||
49 | if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' || | ||
50 | bcode[0x3] != 'S') { | ||
51 | return 0; | ||
52 | } | ||
53 | if (flag != 1) | ||
54 | return ret; | ||
55 | |||
56 | pri_entry = &pri_cfg->entry[0]; | ||
57 | for (i = 0; i < pri_cfg->num_entries; i++) { | ||
58 | if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) | ||
59 | num_valid++; | ||
60 | pri_entry++; | ||
61 | } | ||
62 | |||
63 | if (num_valid == 0) | ||
64 | ret = 0; | ||
65 | |||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | static int | ||
70 | qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job) | ||
71 | { | ||
72 | struct Scsi_Host *host = bsg_job->shost; | ||
73 | scsi_qla_host_t *vha = shost_priv(host); | ||
74 | struct qla_hw_data *ha = vha->hw; | ||
75 | int ret = 0; | ||
76 | uint32_t len; | ||
77 | uint32_t oper; | ||
78 | |||
79 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
80 | |||
81 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
82 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
83 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { | ||
84 | ret = -EBUSY; | ||
85 | goto exit_fcp_prio_cfg; | ||
86 | } | ||
87 | |||
88 | /* Get the sub command */ | ||
89 | oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | ||
90 | |||
91 | /* Only set config is allowed if config memory is not allocated */ | ||
92 | if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) { | ||
93 | ret = -EINVAL; | ||
94 | goto exit_fcp_prio_cfg; | ||
95 | } | ||
96 | switch (oper) { | ||
97 | case QLFC_FCP_PRIO_DISABLE: | ||
98 | if (ha->flags.fcp_prio_enabled) { | ||
99 | ha->flags.fcp_prio_enabled = 0; | ||
100 | ha->fcp_prio_cfg->attributes &= | ||
101 | ~FCP_PRIO_ATTR_ENABLE; | ||
102 | qla24xx_update_all_fcp_prio(vha); | ||
103 | bsg_job->reply->result = DID_OK; | ||
104 | } else { | ||
105 | ret = -EINVAL; | ||
106 | bsg_job->reply->result = (DID_ERROR << 16); | ||
107 | goto exit_fcp_prio_cfg; | ||
108 | } | ||
109 | break; | ||
110 | |||
111 | case QLFC_FCP_PRIO_ENABLE: | ||
112 | if (!ha->flags.fcp_prio_enabled) { | ||
113 | if (ha->fcp_prio_cfg) { | ||
114 | ha->flags.fcp_prio_enabled = 1; | ||
115 | ha->fcp_prio_cfg->attributes |= | ||
116 | FCP_PRIO_ATTR_ENABLE; | ||
117 | qla24xx_update_all_fcp_prio(vha); | ||
118 | bsg_job->reply->result = DID_OK; | ||
119 | } else { | ||
120 | ret = -EINVAL; | ||
121 | bsg_job->reply->result = (DID_ERROR << 16); | ||
122 | goto exit_fcp_prio_cfg; | ||
123 | } | ||
124 | } | ||
125 | break; | ||
126 | |||
127 | case QLFC_FCP_PRIO_GET_CONFIG: | ||
128 | len = bsg_job->reply_payload.payload_len; | ||
129 | if (!len || len > FCP_PRIO_CFG_SIZE) { | ||
130 | ret = -EINVAL; | ||
131 | bsg_job->reply->result = (DID_ERROR << 16); | ||
132 | goto exit_fcp_prio_cfg; | ||
133 | } | ||
134 | |||
135 | bsg_job->reply->result = DID_OK; | ||
136 | bsg_job->reply->reply_payload_rcv_len = | ||
137 | sg_copy_from_buffer( | ||
138 | bsg_job->reply_payload.sg_list, | ||
139 | bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg, | ||
140 | len); | ||
141 | |||
142 | break; | ||
143 | |||
144 | case QLFC_FCP_PRIO_SET_CONFIG: | ||
145 | len = bsg_job->request_payload.payload_len; | ||
146 | if (!len || len > FCP_PRIO_CFG_SIZE) { | ||
147 | bsg_job->reply->result = (DID_ERROR << 16); | ||
148 | ret = -EINVAL; | ||
149 | goto exit_fcp_prio_cfg; | ||
150 | } | ||
151 | |||
152 | if (!ha->fcp_prio_cfg) { | ||
153 | ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); | ||
154 | if (!ha->fcp_prio_cfg) { | ||
155 | qla_printk(KERN_WARNING, ha, | ||
156 | "Unable to allocate memory " | ||
157 | "for fcp prio config data (%x).\n", | ||
158 | FCP_PRIO_CFG_SIZE); | ||
159 | bsg_job->reply->result = (DID_ERROR << 16); | ||
160 | ret = -ENOMEM; | ||
161 | goto exit_fcp_prio_cfg; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); | ||
166 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
167 | bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg, | ||
168 | FCP_PRIO_CFG_SIZE); | ||
169 | |||
170 | /* validate fcp priority data */ | ||
171 | if (!qla24xx_fcp_prio_cfg_valid( | ||
172 | (struct qla_fcp_prio_cfg *) | ||
173 | ha->fcp_prio_cfg, 1)) { | ||
174 | bsg_job->reply->result = (DID_ERROR << 16); | ||
175 | ret = -EINVAL; | ||
176 | /* If buffer was invalidatic int | ||
177 | * fcp_prio_cfg is of no use | ||
178 | */ | ||
179 | vfree(ha->fcp_prio_cfg); | ||
180 | ha->fcp_prio_cfg = NULL; | ||
181 | goto exit_fcp_prio_cfg; | ||
182 | } | ||
183 | |||
184 | ha->flags.fcp_prio_enabled = 0; | ||
185 | if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE) | ||
186 | ha->flags.fcp_prio_enabled = 1; | ||
187 | qla24xx_update_all_fcp_prio(vha); | ||
188 | bsg_job->reply->result = DID_OK; | ||
189 | break; | ||
190 | default: | ||
191 | ret = -EINVAL; | ||
192 | break; | ||
193 | } | ||
194 | exit_fcp_prio_cfg: | ||
195 | bsg_job->job_done(bsg_job); | ||
196 | return ret; | ||
197 | } | ||
38 | static int | 198 | static int |
39 | qla2x00_process_els(struct fc_bsg_job *bsg_job) | 199 | qla2x00_process_els(struct fc_bsg_job *bsg_job) |
40 | { | 200 | { |
@@ -948,6 +1108,9 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | |||
948 | case QL_VND_IIDMA: | 1108 | case QL_VND_IIDMA: |
949 | return qla24xx_iidma(bsg_job); | 1109 | return qla24xx_iidma(bsg_job); |
950 | 1110 | ||
1111 | case QL_VND_FCP_PRIO_CFG_CMD: | ||
1112 | return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job); | ||
1113 | |||
951 | default: | 1114 | default: |
952 | bsg_job->reply->result = (DID_ERROR << 16); | 1115 | bsg_job->reply->result = (DID_ERROR << 16); |
953 | bsg_job->job_done(bsg_job); | 1116 | bsg_job->job_done(bsg_job); |