blob: 5f4cd03797e90e36d78412f106b1119238fc489c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Christof Schmitt553448f2008-06-10 18:20:58 +02002 * zfcp device driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Christof Schmitt553448f2008-06-10 18:20:58 +02004 * Implementation of FSF commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01006 * Copyright IBM Corporation 2002, 2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Christof Schmittecf39d42008-12-25 13:39:53 +01009#define KMSG_COMPONENT "zfcp"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
Stefan Raspl0997f1c2008-10-16 08:23:39 +020012#include <linux/blktrace_api.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "zfcp_ext.h"
Christof Schmitt4318e082009-11-24 16:54:08 +010014#include "zfcp_fc.h"
Christof Schmittdcd20e22009-08-18 15:43:08 +020015#include "zfcp_dbf.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Christof Schmitt287ac012008-07-02 10:56:40 +020017static void zfcp_fsf_request_timeout_handler(unsigned long data)
18{
19 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
Swen Schillig5ffd51a2009-03-02 13:09:04 +010020 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
21 "fsrth_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +020022}
23
24static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
25 unsigned long timeout)
26{
27 fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
28 fsf_req->timer.data = (unsigned long) fsf_req->adapter;
29 fsf_req->timer.expires = jiffies + timeout;
30 add_timer(&fsf_req->timer);
31}
32
33static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
34{
35 BUG_ON(!fsf_req->erp_action);
36 fsf_req->timer.function = zfcp_erp_timeout_handler;
37 fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
38 fsf_req->timer.expires = jiffies + 30 * HZ;
39 add_timer(&fsf_req->timer);
40}
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042/* association between FSF command and FSF QTCB type */
43static u32 fsf_qtcb_type[] = {
44 [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND,
45 [FSF_QTCB_ABORT_FCP_CMND] = FSF_SUPPORT_COMMAND,
46 [FSF_QTCB_OPEN_PORT_WITH_DID] = FSF_SUPPORT_COMMAND,
47 [FSF_QTCB_OPEN_LUN] = FSF_SUPPORT_COMMAND,
48 [FSF_QTCB_CLOSE_LUN] = FSF_SUPPORT_COMMAND,
49 [FSF_QTCB_CLOSE_PORT] = FSF_SUPPORT_COMMAND,
50 [FSF_QTCB_CLOSE_PHYSICAL_PORT] = FSF_SUPPORT_COMMAND,
51 [FSF_QTCB_SEND_ELS] = FSF_SUPPORT_COMMAND,
52 [FSF_QTCB_SEND_GENERIC] = FSF_SUPPORT_COMMAND,
53 [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
54 [FSF_QTCB_EXCHANGE_PORT_DATA] = FSF_PORT_COMMAND,
55 [FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
56 [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
57};
58
Christof Schmitt553448f2008-06-10 18:20:58 +020059static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
60{
Swen Schilligc41f8cb2008-07-02 10:56:39 +020061 u16 subtable = table >> 16;
Christof Schmitt553448f2008-06-10 18:20:58 +020062 u16 rule = table & 0xffff;
Christof Schmittff3b24f2008-10-01 12:42:15 +020063 const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
Christof Schmitt553448f2008-06-10 18:20:58 +020064
Christof Schmittff3b24f2008-10-01 12:42:15 +020065 if (subtable && subtable < ARRAY_SIZE(act_type))
Christof Schmitt553448f2008-06-10 18:20:58 +020066 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020067 "Access denied according to ACT rule type %s, "
68 "rule %d\n", act_type[subtable], rule);
Christof Schmitt553448f2008-06-10 18:20:58 +020069}
70
71static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
72 struct zfcp_port *port)
73{
74 struct fsf_qtcb_header *header = &req->qtcb->header;
75 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020076 "Access denied to port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +020077 (unsigned long long)port->wwpn);
Christof Schmitt553448f2008-06-10 18:20:58 +020078 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
79 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +010080 zfcp_erp_port_access_denied(port, "fspad_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +020081 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
82}
83
84static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
85 struct zfcp_unit *unit)
86{
87 struct fsf_qtcb_header *header = &req->qtcb->header;
88 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020089 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +020090 (unsigned long long)unit->fcp_lun,
91 (unsigned long long)unit->port->wwpn);
Christof Schmitt553448f2008-06-10 18:20:58 +020092 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
93 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +010094 zfcp_erp_unit_access_denied(unit, "fsuad_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +020095 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
96}
97
98static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
99{
Christof Schmittff3b24f2008-10-01 12:42:15 +0200100 dev_err(&req->adapter->ccw_device->dev, "FCP device not "
101 "operational because of an unsupported FC class\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100102 zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +0200103 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
104}
105
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200106/**
107 * zfcp_fsf_req_free - free memory used by fsf request
108 * @fsf_req: pointer to struct zfcp_fsf_req
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200110void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200112 if (likely(req->pool)) {
Swen Schilliga4623c42009-08-18 15:43:15 +0200113 if (likely(req->qtcb))
114 mempool_free(req->qtcb, req->adapter->pool.qtcb_pool);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200115 mempool_free(req, req->pool);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200116 return;
117 }
118
Swen Schilliga4623c42009-08-18 15:43:15 +0200119 if (likely(req->qtcb))
120 kmem_cache_free(zfcp_data.qtcb_cache, req->qtcb);
121 kfree(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200124static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
Swen Schilligecf0c772009-11-24 16:53:58 +0100126 unsigned long flags;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200127 struct fsf_status_read_buffer *sr_buf = req->data;
128 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct zfcp_port *port;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200130 int d_id = sr_buf->d_id & ZFCP_DID_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Swen Schilligecf0c772009-11-24 16:53:58 +0100132 read_lock_irqsave(&adapter->port_list_lock, flags);
133 list_for_each_entry(port, &adapter->port_list, list)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200134 if (port->d_id == d_id) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100135 zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
Swen Schilligecf0c772009-11-24 16:53:58 +0100136 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200137 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100138 read_unlock_irqrestore(&adapter->port_list_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100141static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200142 struct fsf_link_down_info *link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200144 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200146 if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
147 return;
148
149 atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
Christof Schmitt70932932009-04-17 15:08:15 +0200150
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100151 zfcp_scsi_schedule_rports_block(adapter);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200152
153 if (!link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200155
156 switch (link_down->error_code) {
157 case FSF_PSQ_LINK_NO_LIGHT:
158 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200159 "There is no light signal from the local "
160 "fibre channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200161 break;
162 case FSF_PSQ_LINK_WRAP_PLUG:
163 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200164 "There is a wrap plug instead of a fibre "
165 "channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200166 break;
167 case FSF_PSQ_LINK_NO_FCP:
168 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200169 "The adjacent fibre channel node does not "
170 "support FCP\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200171 break;
172 case FSF_PSQ_LINK_FIRMWARE_UPDATE:
173 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200174 "The FCP device is suspended because of a "
175 "firmware update\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200176 break;
177 case FSF_PSQ_LINK_INVALID_WWPN:
178 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200179 "The FCP device detected a WWPN that is "
180 "duplicate or not valid\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200181 break;
182 case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
183 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200184 "The fibre channel fabric does not support NPIV\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200185 break;
186 case FSF_PSQ_LINK_NO_FCP_RESOURCES:
187 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200188 "The FCP adapter cannot support more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200189 break;
190 case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
191 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200192 "The adjacent switch cannot support "
193 "more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200194 break;
195 case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
196 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200197 "The FCP adapter could not log in to the "
198 "fibre channel fabric\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200199 break;
200 case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
201 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200202 "The WWPN assignment file on the FCP adapter "
203 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200204 break;
205 case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
206 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200207 "The mode table on the FCP adapter "
208 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200209 break;
210 case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
211 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200212 "All NPIV ports on the FCP adapter have "
213 "been assigned\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200214 break;
215 default:
216 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200217 "The link between the FCP adapter and "
218 "the FC fabric is down\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200219 }
220out:
221 zfcp_erp_adapter_failed(adapter, id, req);
222}
223
224static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
225{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200226 struct fsf_status_read_buffer *sr_buf = req->data;
227 struct fsf_link_down_info *ldi =
228 (struct fsf_link_down_info *) &sr_buf->payload;
229
230 switch (sr_buf->status_subtype) {
231 case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100232 zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200233 break;
234 case FSF_STATUS_READ_SUB_FDISC_FAILED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100235 zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200236 break;
237 case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100238 zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200239 };
240}
241
242static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
243{
244 struct zfcp_adapter *adapter = req->adapter;
245 struct fsf_status_read_buffer *sr_buf = req->data;
246
247 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
Swen Schillig57717102009-08-18 15:43:21 +0200248 zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf);
Swen Schilliga4623c42009-08-18 15:43:15 +0200249 mempool_free(sr_buf, adapter->pool.status_read_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200250 zfcp_fsf_req_free(req);
251 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
253
Swen Schillig57717102009-08-18 15:43:21 +0200254 zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200255
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200256 switch (sr_buf->status_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 case FSF_STATUS_READ_PORT_CLOSED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200258 zfcp_fsf_status_read_port_closed(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 case FSF_STATUS_READ_INCOMING_ELS:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200261 zfcp_fc_incoming_els(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 case FSF_STATUS_READ_SENSE_DATA_AVAIL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
Christof Schmittff3b24f2008-10-01 12:42:15 +0200266 dev_warn(&adapter->ccw_device->dev,
267 "The error threshold for checksum statistics "
268 "has been exceeded\n");
Swen Schillig57717102009-08-18 15:43:21 +0200269 zfcp_dbf_hba_berr(adapter->dbf, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 case FSF_STATUS_READ_LINK_DOWN:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200272 zfcp_fsf_status_read_link_down(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 case FSF_STATUS_READ_LINK_UP:
Christof Schmitt553448f2008-06-10 18:20:58 +0200275 dev_info(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200276 "The local link has been restored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 /* All ports should be marked as ready to run again */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100278 zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 ZFCP_STATUS_COMMON_RUNNING,
280 ZFCP_SET);
281 zfcp_erp_adapter_reopen(adapter,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200282 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
283 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100284 "fssrh_2", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 break;
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100286 case FSF_STATUS_READ_NOTIFICATION_LOST:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200287 if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100288 zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
289 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200290 if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
Swen Schillig9eae07e2009-11-24 16:54:06 +0100291 queue_work(adapter->work_queue, &adapter->scan_work);
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100292 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 case FSF_STATUS_READ_CFDC_UPDATED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100294 zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200296 case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200297 adapter->adapter_features = sr_buf->payload.word[0];
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200300
Swen Schilliga4623c42009-08-18 15:43:15 +0200301 mempool_free(sr_buf, adapter->pool.status_read_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200302 zfcp_fsf_req_free(req);
Swen Schilligd26ab062008-05-19 12:17:37 +0200303
304 atomic_inc(&adapter->stat_miss);
Swen Schillig45446832009-08-18 15:43:17 +0200305 queue_work(adapter->work_queue, &adapter->stat_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200308static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200310 switch (req->qtcb->header.fsf_status_qual.word[0]) {
311 case FSF_SQ_FCP_RSP_AVAILABLE:
312 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
313 case FSF_SQ_NO_RETRY_POSSIBLE:
314 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
315 return;
316 case FSF_SQ_COMMAND_ABORTED:
317 req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
318 break;
319 case FSF_SQ_NO_RECOM:
320 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200321 "The FCP adapter reported a problem "
322 "that cannot be recovered\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100323 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200324 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200326 /* all non-return stats set FSFREQ_ERROR*/
327 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
328}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200330static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
331{
332 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
333 return;
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200334
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200335 switch (req->qtcb->header.fsf_status) {
336 case FSF_UNKNOWN_COMMAND:
337 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200338 "The FCP adapter does not recognize the command 0x%x\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200339 req->qtcb->header.fsf_command);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100340 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200341 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200344 zfcp_fsf_fsfstatus_qual_eval(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200349static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200351 struct zfcp_adapter *adapter = req->adapter;
352 struct fsf_qtcb *qtcb = req->qtcb;
353 union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Swen Schillig57717102009-08-18 15:43:21 +0200355 zfcp_dbf_hba_fsf_response(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200357 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
358 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
359 ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
360 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
362
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200363 switch (qtcb->prefix.prot_status) {
364 case FSF_PROT_GOOD:
365 case FSF_PROT_FSF_STATUS_PRESENTED:
366 return;
367 case FSF_PROT_QTCB_VERSION_ERROR:
368 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200369 "QTCB version 0x%x not supported by FCP adapter "
370 "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
371 psq->word[0], psq->word[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100372 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200374 case FSF_PROT_ERROR_STATE:
375 case FSF_PROT_SEQ_NUMB_ERROR:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100376 zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200377 req->status |= ZFCP_STATUS_FSFREQ_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200379 case FSF_PROT_UNSUPP_QTCB_TYPE:
380 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200381 "The QTCB type is not supported by the FCP adapter\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100382 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200384 case FSF_PROT_HOST_CONNECTION_INITIALIZING:
385 atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
386 &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200388 case FSF_PROT_DUPLICATE_REQUEST_ID:
389 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200390 "0x%Lx is an ambiguous request identifier\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200391 (unsigned long long)qtcb->bottom.support.req_handle);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100392 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200394 case FSF_PROT_LINK_DOWN:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100395 zfcp_fsf_link_down_info_eval(req, "fspse_5",
396 &psq->link_down_info);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200397 /* FIXME: reopening adapter now? better wait for link up */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100398 zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200400 case FSF_PROT_REEST_QUEUE:
401 /* All ports should be marked as ready to run again */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100402 zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200403 ZFCP_STATUS_COMMON_RUNNING,
404 ZFCP_SET);
405 zfcp_erp_adapter_reopen(adapter,
406 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100407 ZFCP_STATUS_COMMON_ERP_FAILED,
408 "fspse_8", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200409 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200411 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200412 "0x%x is not a valid transfer protocol status\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200413 qtcb->prefix.prot_status);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100414 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200416 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
419/**
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200420 * zfcp_fsf_req_complete - process completion of a FSF request
421 * @fsf_req: The FSF request that has been completed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 *
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200423 * When a request has been completed either from the FCP adapter,
424 * or it has been dismissed due to a queue shutdown, this function
425 * is called to process the completion status and trigger further
426 * events related to the FSF request.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 */
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200428static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200429{
430 if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
431 zfcp_fsf_status_read_handler(req);
432 return;
433 }
434
435 del_timer(&req->timer);
436 zfcp_fsf_protstatus_eval(req);
437 zfcp_fsf_fsfstatus_eval(req);
438 req->handler(req);
439
440 if (req->erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200441 zfcp_erp_notify(req->erp_action, 0);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200442
443 if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
444 zfcp_fsf_req_free(req);
445 else
Swen Schillig058b8642009-08-18 15:43:14 +0200446 complete(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200447}
448
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200449/**
450 * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
451 * @adapter: pointer to struct zfcp_adapter
452 *
453 * Never ever call this without shutting down the adapter first.
454 * Otherwise the adapter would continue using and corrupting s390 storage.
455 * Included BUG_ON() call to ensure this is done.
456 * ERP is supposed to be the only user of this function.
457 */
458void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
459{
460 struct zfcp_fsf_req *req, *tmp;
461 unsigned long flags;
462 LIST_HEAD(remove_queue);
463 unsigned int i;
464
465 BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
466 spin_lock_irqsave(&adapter->req_list_lock, flags);
467 for (i = 0; i < REQUEST_LIST_SIZE; i++)
468 list_splice_init(&adapter->req_list[i], &remove_queue);
469 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
470
471 list_for_each_entry_safe(req, tmp, &remove_queue, list) {
472 list_del(&req->list);
473 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
474 zfcp_fsf_req_complete(req);
475 }
476}
477
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200478static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 struct fsf_qtcb_bottom_config *bottom;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200481 struct zfcp_adapter *adapter = req->adapter;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200482 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200484 bottom = &req->qtcb->bottom.config;
485
486 if (req->data)
487 memcpy(req->data, bottom, sizeof(*bottom));
488
489 fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
490 fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
491 fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
492 fc_host_speed(shost) = bottom->fc_link_speed;
493 fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
494
495 adapter->hydra_version = bottom->adapter_type;
496 adapter->timer_ticks = bottom->timer_interval;
497
498 if (fc_host_permanent_port_name(shost) == -1)
499 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
500
501 switch (bottom->fc_topology) {
502 case FSF_TOPO_P2P:
503 adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
504 adapter->peer_wwpn = bottom->plogi_payload.wwpn;
505 adapter->peer_wwnn = bottom->plogi_payload.wwnn;
506 fc_host_port_type(shost) = FC_PORTTYPE_PTP;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200507 break;
508 case FSF_TOPO_FABRIC:
509 fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200510 break;
511 case FSF_TOPO_AL:
512 fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
Christof Schmittdceab652009-05-15 13:18:18 +0200513 /* fall through */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200514 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200515 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200516 "Unknown or unsupported arbitrated loop "
517 "fibre channel topology detected\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100518 zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200519 return -EIO;
520 }
521
522 return 0;
523}
524
525static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
526{
527 struct zfcp_adapter *adapter = req->adapter;
528 struct fsf_qtcb *qtcb = req->qtcb;
529 struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
530 struct Scsi_Host *shost = adapter->scsi_host;
531
532 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
533 return;
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 adapter->fsf_lic_version = bottom->lic_version;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200536 adapter->adapter_features = bottom->adapter_features;
537 adapter->connection_features = bottom->connection_features;
6f71d9b2005-04-10 23:04:28 -0500538 adapter->peer_wwpn = 0;
539 adapter->peer_wwnn = 0;
540 adapter->peer_d_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200542 switch (qtcb->header.fsf_status) {
543 case FSF_GOOD:
544 if (zfcp_fsf_exchange_config_evaluate(req))
545 return;
Swen Schillig52ef11a2007-08-28 09:31:09 +0200546
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200547 if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
548 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200549 "FCP adapter maximum QTCB size (%d bytes) "
550 "is too small\n",
551 bottom->max_qtcb_size);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100552 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200553 return;
554 }
555 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
556 &adapter->status);
557 break;
558 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200559 fc_host_node_name(shost) = 0;
560 fc_host_port_name(shost) = 0;
561 fc_host_port_id(shost) = 0;
562 fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
Andreas Herrmannad757cd2006-01-13 02:26:11 +0100563 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 adapter->hydra_version = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200565
566 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
567 &adapter->status);
568
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100569 zfcp_fsf_link_down_info_eval(req, "fsecdh2",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200570 &qtcb->header.fsf_status_qual.link_down_info);
571 break;
572 default:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100573 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200574 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
576
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200577 if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 adapter->hardware_version = bottom->hardware_version;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200579 memcpy(fc_host_serial_number(shost), bottom->serial_number,
580 min(FC_SERIAL_NUMBER_SIZE, 17));
581 EBCASC(fc_host_serial_number(shost),
582 min(FC_SERIAL_NUMBER_SIZE, 17));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
584
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200585 if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200586 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200587 "The FCP adapter only supports newer "
588 "control block versions\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100589 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200590 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200592 if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200593 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200594 "The FCP adapter only supports older "
595 "control block versions\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100596 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598}
599
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200600static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200602 struct zfcp_adapter *adapter = req->adapter;
603 struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
604 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200606 if (req->data)
607 memcpy(req->data, bottom, sizeof(*bottom));
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100608
Christof Schmitt02829852009-03-02 13:09:06 +0100609 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100610 fc_host_permanent_port_name(shost) = bottom->wwpn;
Christof Schmitt02829852009-03-02 13:09:06 +0100611 fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
612 } else
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100613 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
614 fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
615 fc_host_supported_speeds(shost) = bottom->supported_speed;
616}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200618static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200620 struct fsf_qtcb *qtcb = req->qtcb;
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100621
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200622 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return;
624
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200625 switch (qtcb->header.fsf_status) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200626 case FSF_GOOD:
627 zfcp_fsf_exchange_port_evaluate(req);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200628 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200629 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200630 zfcp_fsf_exchange_port_evaluate(req);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100631 zfcp_fsf_link_down_info_eval(req, "fsepdh1",
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200632 &qtcb->header.fsf_status_qual.link_down_info);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200633 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
635}
636
Swen Schillig564e1c82009-08-18 15:43:19 +0200637static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200638{
Swen Schillig564e1c82009-08-18 15:43:19 +0200639 struct zfcp_qdio_queue *req_q = &qdio->req_q;
Martin Petermann7001f0c2009-04-17 15:08:12 +0200640
Swen Schillig564e1c82009-08-18 15:43:19 +0200641 spin_lock_bh(&qdio->req_q_lock);
Martin Petermann7001f0c2009-04-17 15:08:12 +0200642 if (atomic_read(&req_q->count))
643 return 1;
Swen Schillig564e1c82009-08-18 15:43:19 +0200644 spin_unlock_bh(&qdio->req_q_lock);
Martin Petermann7001f0c2009-04-17 15:08:12 +0200645 return 0;
646}
647
Swen Schillig564e1c82009-08-18 15:43:19 +0200648static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio)
Martin Petermann7001f0c2009-04-17 15:08:12 +0200649{
Swen Schillig564e1c82009-08-18 15:43:19 +0200650 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200651 long ret;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200652
Swen Schillig564e1c82009-08-18 15:43:19 +0200653 spin_unlock_bh(&qdio->req_q_lock);
654 ret = wait_event_interruptible_timeout(qdio->req_q_wq,
655 zfcp_fsf_sbal_check(qdio), 5 * HZ);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200656 if (ret > 0)
657 return 0;
Christof Schmittcbf1ed02009-07-13 15:06:10 +0200658 if (!ret) {
Swen Schillig564e1c82009-08-18 15:43:19 +0200659 atomic_inc(&qdio->req_q_full);
Christof Schmittcbf1ed02009-07-13 15:06:10 +0200660 /* assume hanging outbound queue, try queue recovery */
661 zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
662 }
Martin Petermann7001f0c2009-04-17 15:08:12 +0200663
Swen Schillig564e1c82009-08-18 15:43:19 +0200664 spin_lock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200665 return -EIO;
666}
667
Swen Schilliga4623c42009-08-18 15:43:15 +0200668static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200669{
670 struct zfcp_fsf_req *req;
Swen Schilliga4623c42009-08-18 15:43:15 +0200671
672 if (likely(pool))
673 req = mempool_alloc(pool, GFP_ATOMIC);
674 else
675 req = kmalloc(sizeof(*req), GFP_ATOMIC);
676
677 if (unlikely(!req))
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200678 return NULL;
Swen Schilliga4623c42009-08-18 15:43:15 +0200679
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200680 memset(req, 0, sizeof(*req));
Christof Schmitt88f2a972008-11-04 16:35:07 +0100681 req->pool = pool;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200682 return req;
683}
684
Swen Schilliga4623c42009-08-18 15:43:15 +0200685static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200686{
Swen Schilliga4623c42009-08-18 15:43:15 +0200687 struct fsf_qtcb *qtcb;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200688
689 if (likely(pool))
690 qtcb = mempool_alloc(pool, GFP_ATOMIC);
691 else
Swen Schilliga4623c42009-08-18 15:43:15 +0200692 qtcb = kmem_cache_alloc(zfcp_data.qtcb_cache, GFP_ATOMIC);
693
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200694 if (unlikely(!qtcb))
695 return NULL;
696
697 memset(qtcb, 0, sizeof(*qtcb));
Swen Schilliga4623c42009-08-18 15:43:15 +0200698 return qtcb;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200699}
700
Swen Schillig564e1c82009-08-18 15:43:19 +0200701static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
Swen Schillig09a46c62009-08-18 15:43:16 +0200702 u32 fsf_cmd, mempool_t *pool)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200704 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +0200705 struct zfcp_qdio_queue *req_q = &qdio->req_q;
706 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schilliga4623c42009-08-18 15:43:15 +0200707 struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200708
709 if (unlikely(!req))
Christof Schmitt1e9b1642009-07-13 15:06:04 +0200710 return ERR_PTR(-ENOMEM);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200711
712 if (adapter->req_no == 0)
713 adapter->req_no++;
714
715 INIT_LIST_HEAD(&req->list);
716 init_timer(&req->timer);
Swen Schillig058b8642009-08-18 15:43:14 +0200717 init_completion(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200718
719 req->adapter = adapter;
720 req->fsf_command = fsf_cmd;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100721 req->req_id = adapter->req_no;
Swen Schillig42428f72009-08-18 15:43:18 +0200722 req->queue_req.sbal_number = 1;
723 req->queue_req.sbal_first = req_q->first;
724 req->queue_req.sbal_last = req_q->first;
725 req->queue_req.sbale_curr = 1;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200726
Swen Schillig564e1c82009-08-18 15:43:19 +0200727 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200728 sbale[0].addr = (void *) req->req_id;
729 sbale[0].flags |= SBAL_FLAGS0_COMMAND;
730
Swen Schilliga4623c42009-08-18 15:43:15 +0200731 if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
732 if (likely(pool))
733 req->qtcb = zfcp_qtcb_alloc(adapter->pool.qtcb_pool);
734 else
735 req->qtcb = zfcp_qtcb_alloc(NULL);
736
737 if (unlikely(!req->qtcb)) {
738 zfcp_fsf_req_free(req);
739 return ERR_PTR(-ENOMEM);
740 }
741
Swen Schillig564e1c82009-08-18 15:43:19 +0200742 req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200743 req->qtcb->prefix.req_id = req->req_id;
744 req->qtcb->prefix.ulp_info = 26;
745 req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
746 req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
747 req->qtcb->header.req_handle = req->req_id;
748 req->qtcb->header.fsf_command = req->fsf_command;
749 req->seq_no = adapter->fsf_req_seq_no;
750 req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
751 sbale[1].addr = (void *) req->qtcb;
752 sbale[1].length = sizeof(struct fsf_qtcb);
753 }
754
755 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
756 zfcp_fsf_req_free(req);
757 return ERR_PTR(-EIO);
758 }
759
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200760 return req;
761}
762
763static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
764{
765 struct zfcp_adapter *adapter = req->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +0200766 struct zfcp_qdio *qdio = adapter->qdio;
Martin Petermann135ea132009-04-17 15:08:01 +0200767 unsigned long flags;
768 int idx;
769 int with_qtcb = (req->qtcb != NULL);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200770
771 /* put allocated FSF request into hash table */
Heiko Carstens45316a82008-11-04 16:35:06 +0100772 spin_lock_irqsave(&adapter->req_list_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200773 idx = zfcp_reqlist_hash(req->req_id);
774 list_add_tail(&req->list, &adapter->req_list[idx]);
Heiko Carstens45316a82008-11-04 16:35:06 +0100775 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200776
Swen Schillig564e1c82009-08-18 15:43:19 +0200777 req->queue_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200778 req->issued = get_clock();
Swen Schillig564e1c82009-08-18 15:43:19 +0200779 if (zfcp_qdio_send(qdio, &req->queue_req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200780 del_timer(&req->timer);
Christof Schmitt37651382008-11-04 16:35:08 +0100781 spin_lock_irqsave(&adapter->req_list_lock, flags);
782 /* lookup request again, list might have changed */
783 if (zfcp_reqlist_find_safe(adapter, req))
784 zfcp_reqlist_remove(adapter, req);
785 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100786 zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200787 return -EIO;
788 }
789
790 /* Don't increase for unsolicited status */
Martin Petermann135ea132009-04-17 15:08:01 +0200791 if (with_qtcb)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200792 adapter->fsf_req_seq_no++;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100793 adapter->req_no++;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200794
795 return 0;
796}
797
798/**
799 * zfcp_fsf_status_read - send status read request
800 * @adapter: pointer to struct zfcp_adapter
801 * @req_flags: request flags
802 * Returns: 0 on success, ERROR otherwise
803 */
Swen Schillig564e1c82009-08-18 15:43:19 +0200804int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200805{
Swen Schillig564e1c82009-08-18 15:43:19 +0200806 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200807 struct zfcp_fsf_req *req;
808 struct fsf_status_read_buffer *sr_buf;
Swen Schillig44cc76f2008-10-01 12:42:16 +0200809 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200810 int retval = -EIO;
811
Swen Schillig564e1c82009-08-18 15:43:19 +0200812 spin_lock_bh(&qdio->req_q_lock);
813 if (zfcp_fsf_req_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Swen Schillig564e1c82009-08-18 15:43:19 +0200816 req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
Swen Schilliga4623c42009-08-18 15:43:15 +0200817 adapter->pool.status_read_req);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +0200818 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200819 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 goto out;
821 }
822
Swen Schillig564e1c82009-08-18 15:43:19 +0200823 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200824 sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
Swen Schillig42428f72009-08-18 15:43:18 +0200825 req->queue_req.sbale_curr = 2;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200826
Swen Schilliga4623c42009-08-18 15:43:15 +0200827 sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200828 if (!sr_buf) {
829 retval = -ENOMEM;
830 goto failed_buf;
831 }
832 memset(sr_buf, 0, sizeof(*sr_buf));
833 req->data = sr_buf;
Swen Schillig564e1c82009-08-18 15:43:19 +0200834 sbale = zfcp_qdio_sbale_curr(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200835 sbale->addr = (void *) sr_buf;
836 sbale->length = sizeof(*sr_buf);
837
838 retval = zfcp_fsf_req_send(req);
839 if (retval)
840 goto failed_req_send;
841
842 goto out;
843
844failed_req_send:
Swen Schilliga4623c42009-08-18 15:43:15 +0200845 mempool_free(sr_buf, adapter->pool.status_read_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200846failed_buf:
847 zfcp_fsf_req_free(req);
Swen Schillig57717102009-08-18 15:43:21 +0200848 zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200849out:
Swen Schillig564e1c82009-08-18 15:43:19 +0200850 spin_unlock_bh(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return retval;
852}
853
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200854static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200856 struct zfcp_unit *unit = req->data;
857 union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200859 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
860 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200862 switch (req->qtcb->header.fsf_status) {
863 case FSF_PORT_HANDLE_NOT_VALID:
864 if (fsq->word[0] == fsq->word[1]) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100865 zfcp_erp_adapter_reopen(unit->port->adapter, 0,
866 "fsafch1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200867 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200870 case FSF_LUN_HANDLE_NOT_VALID:
871 if (fsq->word[0] == fsq->word[1]) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100872 zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200873 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200876 case FSF_FCP_COMMAND_DOES_NOT_EXIST:
877 req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200879 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100880 zfcp_erp_port_boxed(unit->port, "fsafch3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200881 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
882 ZFCP_STATUS_FSFREQ_RETRY;
883 break;
884 case FSF_LUN_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100885 zfcp_erp_unit_boxed(unit, "fsafch4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200886 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
887 ZFCP_STATUS_FSFREQ_RETRY;
888 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200890 switch (fsq->word[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schillig6f53a2d2009-08-18 15:43:23 +0200892 zfcp_fc_test_link(unit->port);
Christof Schmittdceab652009-05-15 13:18:18 +0200893 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200895 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 break;
897 }
898 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 case FSF_GOOD:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200900 req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
901 break;
902 }
903}
904
905/**
906 * zfcp_fsf_abort_fcp_command - abort running SCSI command
907 * @old_req_id: unsigned long
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200908 * @unit: pointer to struct zfcp_unit
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200909 * Returns: pointer to struct zfcp_fsf_req
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200910 */
911
912struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
Christof Schmitt63caf362009-03-02 13:09:00 +0100913 struct zfcp_unit *unit)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200914{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200915 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200916 struct zfcp_fsf_req *req = NULL;
Swen Schillig564e1c82009-08-18 15:43:19 +0200917 struct zfcp_qdio *qdio = unit->port->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200918
Swen Schillig564e1c82009-08-18 15:43:19 +0200919 spin_lock_bh(&qdio->req_q_lock);
920 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200921 goto out;
Swen Schillig564e1c82009-08-18 15:43:19 +0200922 req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
923 qdio->adapter->pool.scsi_abort);
Swen Schillig633528c2008-11-26 18:07:37 +0100924 if (IS_ERR(req)) {
925 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200926 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +0100927 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200928
929 if (unlikely(!(atomic_read(&unit->status) &
930 ZFCP_STATUS_COMMON_UNBLOCKED)))
931 goto out_error_free;
932
Swen Schillig564e1c82009-08-18 15:43:19 +0200933 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200934 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
935 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
936
937 req->data = unit;
938 req->handler = zfcp_fsf_abort_fcp_command_handler;
939 req->qtcb->header.lun_handle = unit->handle;
940 req->qtcb->header.port_handle = unit->port->handle;
941 req->qtcb->bottom.support.req_handle = (u64) old_req_id;
942
943 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
944 if (!zfcp_fsf_req_send(req))
945 goto out;
946
947out_error_free:
948 zfcp_fsf_req_free(req);
949 req = NULL;
950out:
Swen Schillig564e1c82009-08-18 15:43:19 +0200951 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200952 return req;
953}
954
955static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
956{
957 struct zfcp_adapter *adapter = req->adapter;
958 struct zfcp_send_ct *send_ct = req->data;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200959 struct fsf_qtcb_header *header = &req->qtcb->header;
960
961 send_ct->status = -EINVAL;
962
963 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
964 goto skip_fsfstatus;
965
966 switch (header->fsf_status) {
967 case FSF_GOOD:
Swen Schillig57717102009-08-18 15:43:21 +0200968 zfcp_dbf_san_ct_response(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200969 send_ct->status = 0;
970 break;
971 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
972 zfcp_fsf_class_not_supp(req);
973 break;
974 case FSF_ADAPTER_STATUS_AVAILABLE:
975 switch (header->fsf_status_qual.word[0]){
976 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200977 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
978 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
979 break;
980 }
981 break;
982 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200983 break;
984 case FSF_PORT_BOXED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200985 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
986 ZFCP_STATUS_FSFREQ_RETRY;
987 break;
988 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100989 zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
Christof Schmittdceab652009-05-15 13:18:18 +0200990 /* fall through */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200991 case FSF_GENERIC_COMMAND_REJECTED:
992 case FSF_PAYLOAD_SIZE_MISMATCH:
993 case FSF_REQUEST_SIZE_TOO_LARGE:
994 case FSF_RESPONSE_SIZE_TOO_LARGE:
995 case FSF_SBAL_MISMATCH:
996 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
997 break;
998 }
999
1000skip_fsfstatus:
1001 if (send_ct->handler)
1002 send_ct->handler(send_ct->handler_data);
1003}
1004
Christof Schmitt426f6052009-07-13 15:06:06 +02001005static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
1006 struct scatterlist *sg_req,
1007 struct scatterlist *sg_resp)
1008{
1009 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
1010 sbale[2].addr = sg_virt(sg_req);
1011 sbale[2].length = sg_req->length;
1012 sbale[3].addr = sg_virt(sg_resp);
1013 sbale[3].length = sg_resp->length;
1014 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
1015}
1016
1017static int zfcp_fsf_one_sbal(struct scatterlist *sg)
1018{
1019 return sg_is_last(sg) && sg->length <= PAGE_SIZE;
1020}
1021
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001022static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
1023 struct scatterlist *sg_req,
1024 struct scatterlist *sg_resp,
1025 int max_sbals)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001026{
Swen Schillig42428f72009-08-18 15:43:18 +02001027 struct zfcp_adapter *adapter = req->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +02001028 struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio,
Swen Schillig42428f72009-08-18 15:43:18 +02001029 &req->queue_req);
1030 u32 feat = adapter->adapter_features;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001031 int bytes;
1032
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001033 if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
Christof Schmitt426f6052009-07-13 15:06:06 +02001034 if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001035 return -EOPNOTSUPP;
1036
Christof Schmitt426f6052009-07-13 15:06:06 +02001037 zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
1038 return 0;
1039 }
1040
1041 /* use single, unchained SBAL if it can hold the request */
1042 if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
1043 zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001044 return 0;
1045 }
1046
Swen Schillig564e1c82009-08-18 15:43:19 +02001047 bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,
Swen Schillig42428f72009-08-18 15:43:18 +02001048 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001049 sg_req, max_sbals);
1050 if (bytes <= 0)
Christof Schmitt9072df42009-07-13 15:06:07 +02001051 return -EIO;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001052 req->qtcb->bottom.support.req_buf_length = bytes;
Swen Schillig42428f72009-08-18 15:43:18 +02001053 req->queue_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001054
Swen Schillig564e1c82009-08-18 15:43:19 +02001055 bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,
Swen Schillig42428f72009-08-18 15:43:18 +02001056 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001057 sg_resp, max_sbals);
Christof Schmittb1a58982009-09-24 10:23:21 +02001058 req->qtcb->bottom.support.resp_buf_length = bytes;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001059 if (bytes <= 0)
Christof Schmitt9072df42009-07-13 15:06:07 +02001060 return -EIO;
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001061
Christof Schmittb1a58982009-09-24 10:23:21 +02001062 return 0;
1063}
1064
1065static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
1066 struct scatterlist *sg_req,
1067 struct scatterlist *sg_resp,
1068 int max_sbals)
1069{
1070 int ret;
1071
1072 ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
1073 if (ret)
1074 return ret;
1075
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001076 /* common settings for ct/gs and els requests */
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001077 req->qtcb->bottom.support.service_class = FSF_CLASS_3;
1078 req->qtcb->bottom.support.timeout = 2 * R_A_TOV;
Christof Schmitt9d385002009-10-13 10:44:10 +02001079 zfcp_fsf_start_timer(req, (2 * R_A_TOV + 10) * HZ);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001080
1081 return 0;
1082}
1083
1084/**
1085 * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1086 * @ct: pointer to struct zfcp_send_ct with data for request
1087 * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001088 */
Christof Schmitt799b76d2009-08-18 15:43:20 +02001089int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001090{
Swen Schillig5ab944f2008-10-01 12:42:17 +02001091 struct zfcp_wka_port *wka_port = ct->wka_port;
Swen Schillig564e1c82009-08-18 15:43:19 +02001092 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001093 struct zfcp_fsf_req *req;
1094 int ret = -EIO;
1095
Swen Schillig564e1c82009-08-18 15:43:19 +02001096 spin_lock_bh(&qdio->req_q_lock);
1097 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001098 goto out;
1099
Swen Schillig564e1c82009-08-18 15:43:19 +02001100 req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool);
Swen Schillig09a46c62009-08-18 15:43:16 +02001101
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001102 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001103 ret = PTR_ERR(req);
1104 goto out;
1105 }
1106
Swen Schillig09a46c62009-08-18 15:43:16 +02001107 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmittb1a58982009-09-24 10:23:21 +02001108 ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
1109 FSF_MAX_SBALS_PER_REQ);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001110 if (ret)
1111 goto failed_send;
1112
1113 req->handler = zfcp_fsf_send_ct_handler;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001114 req->qtcb->header.port_handle = wka_port->handle;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001115 req->data = ct;
1116
Swen Schillig57717102009-08-18 15:43:21 +02001117 zfcp_dbf_san_ct_request(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001118
1119 ret = zfcp_fsf_req_send(req);
1120 if (ret)
1121 goto failed_send;
1122
1123 goto out;
1124
1125failed_send:
1126 zfcp_fsf_req_free(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001127out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001128 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001129 return ret;
1130}
1131
1132static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
1133{
1134 struct zfcp_send_els *send_els = req->data;
1135 struct zfcp_port *port = send_els->port;
1136 struct fsf_qtcb_header *header = &req->qtcb->header;
1137
1138 send_els->status = -EINVAL;
1139
1140 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
1141 goto skip_fsfstatus;
1142
1143 switch (header->fsf_status) {
1144 case FSF_GOOD:
Swen Schillig57717102009-08-18 15:43:21 +02001145 zfcp_dbf_san_els_response(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001146 send_els->status = 0;
1147 break;
1148 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1149 zfcp_fsf_class_not_supp(req);
1150 break;
1151 case FSF_ADAPTER_STATUS_AVAILABLE:
1152 switch (header->fsf_status_qual.word[0]){
1153 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1154 if (port && (send_els->ls_code != ZFCP_LS_ADISC))
Swen Schillig6f53a2d2009-08-18 15:43:23 +02001155 zfcp_fc_test_link(port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001156 /*fall through */
1157 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1158 case FSF_SQ_RETRY_IF_POSSIBLE:
1159 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1160 break;
1161 }
1162 break;
1163 case FSF_ELS_COMMAND_REJECTED:
1164 case FSF_PAYLOAD_SIZE_MISMATCH:
1165 case FSF_REQUEST_SIZE_TOO_LARGE:
1166 case FSF_RESPONSE_SIZE_TOO_LARGE:
1167 break;
1168 case FSF_ACCESS_DENIED:
Christof Schmittdc577d52009-05-15 13:18:22 +02001169 if (port)
1170 zfcp_fsf_access_denied_port(req, port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001171 break;
1172 case FSF_SBAL_MISMATCH:
1173 /* should never occure, avoided in zfcp_fsf_send_els */
1174 /* fall through */
1175 default:
1176 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1177 break;
1178 }
1179skip_fsfstatus:
1180 if (send_els->handler)
1181 send_els->handler(send_els->handler_data);
1182}
1183
1184/**
1185 * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1186 * @els: pointer to struct zfcp_send_els with data for the command
1187 */
1188int zfcp_fsf_send_els(struct zfcp_send_els *els)
1189{
1190 struct zfcp_fsf_req *req;
Swen Schillig564e1c82009-08-18 15:43:19 +02001191 struct zfcp_qdio *qdio = els->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001192 int ret = -EIO;
1193
Swen Schillig564e1c82009-08-18 15:43:19 +02001194 spin_lock_bh(&qdio->req_q_lock);
1195 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001196 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001197
Swen Schillig564e1c82009-08-18 15:43:19 +02001198 req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001199
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001200 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001201 ret = PTR_ERR(req);
1202 goto out;
1203 }
1204
Swen Schillig09a46c62009-08-18 15:43:16 +02001205 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmittb1a58982009-09-24 10:23:21 +02001206 ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2);
Swen Schillig44cc76f2008-10-01 12:42:16 +02001207
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001208 if (ret)
1209 goto failed_send;
1210
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001211 req->qtcb->bottom.support.d_id = els->d_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001212 req->handler = zfcp_fsf_send_els_handler;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001213 req->data = els;
1214
Swen Schillig57717102009-08-18 15:43:21 +02001215 zfcp_dbf_san_els_request(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001216
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001217 ret = zfcp_fsf_req_send(req);
1218 if (ret)
1219 goto failed_send;
1220
1221 goto out;
1222
1223failed_send:
1224 zfcp_fsf_req_free(req);
1225out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001226 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001227 return ret;
1228}
1229
1230int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
1231{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001232 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001233 struct zfcp_fsf_req *req;
Swen Schillig564e1c82009-08-18 15:43:19 +02001234 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001235 int retval = -EIO;
1236
Swen Schillig564e1c82009-08-18 15:43:19 +02001237 spin_lock_bh(&qdio->req_q_lock);
1238 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001239 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001240
Swen Schillig564e1c82009-08-18 15:43:19 +02001241 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
1242 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001243
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001244 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001245 retval = PTR_ERR(req);
1246 goto out;
1247 }
1248
Swen Schillig09a46c62009-08-18 15:43:16 +02001249 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001250 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001251 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1252 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1253
1254 req->qtcb->bottom.config.feature_selection =
1255 FSF_FEATURE_CFDC |
1256 FSF_FEATURE_LUN_SHARING |
1257 FSF_FEATURE_NOTIFICATION_LOST |
1258 FSF_FEATURE_UPDATE_ALERT;
1259 req->erp_action = erp_action;
1260 req->handler = zfcp_fsf_exchange_config_data_handler;
1261 erp_action->fsf_req = req;
1262
Christof Schmitt287ac012008-07-02 10:56:40 +02001263 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001264 retval = zfcp_fsf_req_send(req);
1265 if (retval) {
1266 zfcp_fsf_req_free(req);
1267 erp_action->fsf_req = NULL;
1268 }
1269out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001270 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001271 return retval;
1272}
1273
Swen Schillig564e1c82009-08-18 15:43:19 +02001274int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001275 struct fsf_qtcb_bottom_config *data)
1276{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001277 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001278 struct zfcp_fsf_req *req = NULL;
1279 int retval = -EIO;
1280
Swen Schillig564e1c82009-08-18 15:43:19 +02001281 spin_lock_bh(&qdio->req_q_lock);
1282 if (zfcp_fsf_req_sbal_get(qdio))
Christof Schmittada81b72009-04-17 15:08:03 +02001283 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001284
Swen Schillig564e1c82009-08-18 15:43:19 +02001285 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001286
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001287 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001288 retval = PTR_ERR(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001289 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001290 }
1291
Swen Schillig564e1c82009-08-18 15:43:19 +02001292 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001293 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1294 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1295 req->handler = zfcp_fsf_exchange_config_data_handler;
1296
1297 req->qtcb->bottom.config.feature_selection =
1298 FSF_FEATURE_CFDC |
1299 FSF_FEATURE_LUN_SHARING |
1300 FSF_FEATURE_NOTIFICATION_LOST |
1301 FSF_FEATURE_UPDATE_ALERT;
1302
1303 if (data)
1304 req->data = data;
1305
1306 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1307 retval = zfcp_fsf_req_send(req);
Swen Schillig564e1c82009-08-18 15:43:19 +02001308 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001309 if (!retval)
Swen Schillig058b8642009-08-18 15:43:14 +02001310 wait_for_completion(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001311
1312 zfcp_fsf_req_free(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001313 return retval;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001314
Christof Schmittada81b72009-04-17 15:08:03 +02001315out_unlock:
Swen Schillig564e1c82009-08-18 15:43:19 +02001316 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001317 return retval;
1318}
1319
1320/**
1321 * zfcp_fsf_exchange_port_data - request information about local port
1322 * @erp_action: ERP action for the adapter for which port data is requested
1323 * Returns: 0 on success, error otherwise
1324 */
1325int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
1326{
Swen Schillig564e1c82009-08-18 15:43:19 +02001327 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schillig44cc76f2008-10-01 12:42:16 +02001328 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001329 struct zfcp_fsf_req *req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001330 int retval = -EIO;
1331
Swen Schillig564e1c82009-08-18 15:43:19 +02001332 if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001333 return -EOPNOTSUPP;
1334
Swen Schillig564e1c82009-08-18 15:43:19 +02001335 spin_lock_bh(&qdio->req_q_lock);
1336 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001337 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001338
Swen Schillig564e1c82009-08-18 15:43:19 +02001339 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
1340 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001341
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001342 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001343 retval = PTR_ERR(req);
1344 goto out;
1345 }
1346
Swen Schillig09a46c62009-08-18 15:43:16 +02001347 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001348 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001349 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1350 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1351
1352 req->handler = zfcp_fsf_exchange_port_data_handler;
1353 req->erp_action = erp_action;
1354 erp_action->fsf_req = req;
1355
Christof Schmitt287ac012008-07-02 10:56:40 +02001356 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001357 retval = zfcp_fsf_req_send(req);
1358 if (retval) {
1359 zfcp_fsf_req_free(req);
1360 erp_action->fsf_req = NULL;
1361 }
1362out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001363 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001364 return retval;
1365}
1366
1367/**
1368 * zfcp_fsf_exchange_port_data_sync - request information about local port
Swen Schillig564e1c82009-08-18 15:43:19 +02001369 * @qdio: pointer to struct zfcp_qdio
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001370 * @data: pointer to struct fsf_qtcb_bottom_port
1371 * Returns: 0 on success, error otherwise
1372 */
Swen Schillig564e1c82009-08-18 15:43:19 +02001373int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001374 struct fsf_qtcb_bottom_port *data)
1375{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001376 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001377 struct zfcp_fsf_req *req = NULL;
1378 int retval = -EIO;
1379
Swen Schillig564e1c82009-08-18 15:43:19 +02001380 if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001381 return -EOPNOTSUPP;
1382
Swen Schillig564e1c82009-08-18 15:43:19 +02001383 spin_lock_bh(&qdio->req_q_lock);
1384 if (zfcp_fsf_req_sbal_get(qdio))
Christof Schmittada81b72009-04-17 15:08:03 +02001385 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001386
Swen Schillig564e1c82009-08-18 15:43:19 +02001387 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001388
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001389 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001390 retval = PTR_ERR(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001391 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001392 }
1393
1394 if (data)
1395 req->data = data;
1396
Swen Schillig564e1c82009-08-18 15:43:19 +02001397 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001398 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1399 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1400
1401 req->handler = zfcp_fsf_exchange_port_data_handler;
1402 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1403 retval = zfcp_fsf_req_send(req);
Swen Schillig564e1c82009-08-18 15:43:19 +02001404 spin_unlock_bh(&qdio->req_q_lock);
Christof Schmittada81b72009-04-17 15:08:03 +02001405
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001406 if (!retval)
Swen Schillig058b8642009-08-18 15:43:14 +02001407 wait_for_completion(&req->completion);
1408
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001409 zfcp_fsf_req_free(req);
1410
1411 return retval;
Christof Schmittada81b72009-04-17 15:08:03 +02001412
1413out_unlock:
Swen Schillig564e1c82009-08-18 15:43:19 +02001414 spin_unlock_bh(&qdio->req_q_lock);
Christof Schmittada81b72009-04-17 15:08:03 +02001415 return retval;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001416}
1417
1418static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
1419{
1420 struct zfcp_port *port = req->data;
1421 struct fsf_qtcb_header *header = &req->qtcb->header;
1422 struct fsf_plogi *plogi;
1423
1424 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Martin Petermanna17c5852009-05-15 13:18:19 +02001425 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001426
1427 switch (header->fsf_status) {
1428 case FSF_PORT_ALREADY_OPEN:
1429 break;
1430 case FSF_ACCESS_DENIED:
1431 zfcp_fsf_access_denied_port(req, port);
1432 break;
1433 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1434 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001435 "Not enough FCP adapter resources to open "
Swen Schillig7ba58c92008-10-01 12:42:18 +02001436 "remote port 0x%016Lx\n",
1437 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001438 zfcp_erp_port_failed(port, "fsoph_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001439 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1440 break;
1441 case FSF_ADAPTER_STATUS_AVAILABLE:
1442 switch (header->fsf_status_qual.word[0]) {
1443 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1444 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001445 case FSF_SQ_NO_RETRY_POSSIBLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001446 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1447 break;
1448 }
1449 break;
1450 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 port->handle = header->port_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
1453 ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001454 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1455 ZFCP_STATUS_COMMON_ACCESS_BOXED,
1456 &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 /* check whether D_ID has changed during open */
1458 /*
1459 * FIXME: This check is not airtight, as the FCP channel does
1460 * not monitor closures of target port connections caused on
1461 * the remote side. Thus, they might miss out on invalidating
1462 * locally cached WWPNs (and other N_Port parameters) of gone
1463 * target ports. So, our heroic attempt to make things safe
1464 * could be undermined by 'open port' response data tagged with
1465 * obsolete WWPNs. Another reason to monitor potential
1466 * connection closures ourself at least (by interpreting
1467 * incoming ELS' and unsolicited status). It just crosses my
1468 * mind that one should be able to cross-check by means of
1469 * another GID_PN straight after a port has been opened.
1470 * Alternately, an ADISC/PDISC ELS should suffice, as well.
1471 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001472 plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001473 if (req->qtcb->bottom.support.els1_length >=
1474 FSF_PLOGI_MIN_LEN) {
Christof Schmitt10d00f72009-10-13 10:44:09 +02001475 if (plogi->serv_param.wwpn != port->wwpn) {
Christof Schmittb98478d2008-12-19 16:56:59 +01001476 port->d_id = 0;
Christof Schmitt10d00f72009-10-13 10:44:09 +02001477 dev_warn(&port->adapter->ccw_device->dev,
1478 "A port opened with WWPN 0x%016Lx "
1479 "returned data that identifies it as "
1480 "WWPN 0x%016Lx\n",
1481 (unsigned long long) port->wwpn,
1482 (unsigned long long)
1483 plogi->serv_param.wwpn);
1484 } else {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001485 port->wwnn = plogi->serv_param.wwnn;
1486 zfcp_fc_plogi_evaluate(port, plogi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 }
1488 }
1489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 case FSF_UNKNOWN_OP_SUBTYPE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001491 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 break;
1493 }
Martin Petermanna17c5852009-05-15 13:18:19 +02001494
1495out:
Swen Schilligf3450c72009-11-24 16:53:59 +01001496 put_device(&port->sysfs_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497}
1498
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001499/**
1500 * zfcp_fsf_open_port - create and send open port request
1501 * @erp_action: pointer to struct zfcp_erp_action
1502 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001504int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001506 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02001507 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Martin Petermanna17c5852009-05-15 13:18:19 +02001508 struct zfcp_port *port = erp_action->port;
Swen Schillig564e1c82009-08-18 15:43:19 +02001509 struct zfcp_fsf_req *req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001510 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Swen Schillig564e1c82009-08-18 15:43:19 +02001512 spin_lock_bh(&qdio->req_q_lock);
1513 if (zfcp_fsf_req_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Swen Schillig564e1c82009-08-18 15:43:19 +02001516 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
1517 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001518
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001519 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001520 retval = PTR_ERR(req);
1521 goto out;
1522 }
1523
Swen Schillig09a46c62009-08-18 15:43:16 +02001524 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001525 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1527 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1528
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001529 req->handler = zfcp_fsf_open_port_handler;
Martin Petermanna17c5852009-05-15 13:18:19 +02001530 req->qtcb->bottom.support.d_id = port->d_id;
1531 req->data = port;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001532 req->erp_action = erp_action;
1533 erp_action->fsf_req = req;
Swen Schilligf3450c72009-11-24 16:53:59 +01001534 get_device(&port->sysfs_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Christof Schmitt287ac012008-07-02 10:56:40 +02001536 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001537 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001539 zfcp_fsf_req_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 erp_action->fsf_req = NULL;
Swen Schilligf3450c72009-11-24 16:53:59 +01001541 put_device(&port->sysfs_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001543out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001544 spin_unlock_bh(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 return retval;
1546}
1547
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001548static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001550 struct zfcp_port *port = req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001552 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001553 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001555 switch (req->qtcb->header.fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001557 zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001558 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 case FSF_GOOD:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001563 zfcp_erp_modify_port_status(port, "fscph_2", req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 ZFCP_STATUS_COMMON_OPEN,
1565 ZFCP_CLEAR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568}
1569
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001570/**
1571 * zfcp_fsf_close_port - create and send close port request
1572 * @erp_action: pointer to struct zfcp_erp_action
1573 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001575int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001577 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02001578 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001579 struct zfcp_fsf_req *req;
1580 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Swen Schillig564e1c82009-08-18 15:43:19 +02001582 spin_lock_bh(&qdio->req_q_lock);
1583 if (zfcp_fsf_req_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
Swen Schillig564e1c82009-08-18 15:43:19 +02001586 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
1587 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001588
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001589 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001590 retval = PTR_ERR(req);
1591 goto out;
1592 }
1593
Swen Schillig09a46c62009-08-18 15:43:16 +02001594 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001595 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1597 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1598
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001599 req->handler = zfcp_fsf_close_port_handler;
1600 req->data = erp_action->port;
1601 req->erp_action = erp_action;
1602 req->qtcb->header.port_handle = erp_action->port->handle;
1603 erp_action->fsf_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Christof Schmitt287ac012008-07-02 10:56:40 +02001605 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001606 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001608 zfcp_fsf_req_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 erp_action->fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001611out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001612 spin_unlock_bh(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 return retval;
1614}
1615
Swen Schillig5ab944f2008-10-01 12:42:17 +02001616static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
1617{
1618 struct zfcp_wka_port *wka_port = req->data;
1619 struct fsf_qtcb_header *header = &req->qtcb->header;
1620
1621 if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
1622 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1623 goto out;
1624 }
1625
1626 switch (header->fsf_status) {
1627 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1628 dev_warn(&req->adapter->ccw_device->dev,
1629 "Opening WKA port 0x%x failed\n", wka_port->d_id);
Christof Schmittdceab652009-05-15 13:18:18 +02001630 /* fall through */
Swen Schillig5ab944f2008-10-01 12:42:17 +02001631 case FSF_ADAPTER_STATUS_AVAILABLE:
1632 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Christof Schmittdceab652009-05-15 13:18:18 +02001633 /* fall through */
Swen Schillig5ab944f2008-10-01 12:42:17 +02001634 case FSF_ACCESS_DENIED:
1635 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1636 break;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001637 case FSF_GOOD:
1638 wka_port->handle = header->port_handle;
Swen Schillig27f492c2009-07-13 15:06:13 +02001639 /* fall through */
1640 case FSF_PORT_ALREADY_OPEN:
Swen Schillig5ab944f2008-10-01 12:42:17 +02001641 wka_port->status = ZFCP_WKA_PORT_ONLINE;
1642 }
1643out:
1644 wake_up(&wka_port->completion_wq);
1645}
1646
1647/**
1648 * zfcp_fsf_open_wka_port - create and send open wka-port request
1649 * @wka_port: pointer to struct zfcp_wka_port
1650 * Returns: 0 on success, error otherwise
1651 */
1652int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
1653{
1654 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02001655 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001656 struct zfcp_fsf_req *req;
1657 int retval = -EIO;
1658
Swen Schillig564e1c82009-08-18 15:43:19 +02001659 spin_lock_bh(&qdio->req_q_lock);
1660 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schillig5ab944f2008-10-01 12:42:17 +02001661 goto out;
1662
Swen Schillig564e1c82009-08-18 15:43:19 +02001663 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
1664 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001665
Swen Schillig5ab944f2008-10-01 12:42:17 +02001666 if (unlikely(IS_ERR(req))) {
1667 retval = PTR_ERR(req);
1668 goto out;
1669 }
1670
Swen Schillig09a46c62009-08-18 15:43:16 +02001671 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001672 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001673 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1674 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1675
1676 req->handler = zfcp_fsf_open_wka_port_handler;
1677 req->qtcb->bottom.support.d_id = wka_port->d_id;
1678 req->data = wka_port;
1679
1680 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1681 retval = zfcp_fsf_req_send(req);
1682 if (retval)
1683 zfcp_fsf_req_free(req);
1684out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001685 spin_unlock_bh(&qdio->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001686 return retval;
1687}
1688
1689static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
1690{
1691 struct zfcp_wka_port *wka_port = req->data;
1692
1693 if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
1694 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001695 zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001696 }
1697
1698 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1699 wake_up(&wka_port->completion_wq);
1700}
1701
1702/**
1703 * zfcp_fsf_close_wka_port - create and send close wka port request
1704 * @erp_action: pointer to struct zfcp_erp_action
1705 * Returns: 0 on success, error otherwise
1706 */
1707int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
1708{
1709 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02001710 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001711 struct zfcp_fsf_req *req;
1712 int retval = -EIO;
1713
Swen Schillig564e1c82009-08-18 15:43:19 +02001714 spin_lock_bh(&qdio->req_q_lock);
1715 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schillig5ab944f2008-10-01 12:42:17 +02001716 goto out;
1717
Swen Schillig564e1c82009-08-18 15:43:19 +02001718 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
1719 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001720
Swen Schillig5ab944f2008-10-01 12:42:17 +02001721 if (unlikely(IS_ERR(req))) {
1722 retval = PTR_ERR(req);
1723 goto out;
1724 }
1725
Swen Schillig09a46c62009-08-18 15:43:16 +02001726 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001727 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001728 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1729 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1730
1731 req->handler = zfcp_fsf_close_wka_port_handler;
1732 req->data = wka_port;
1733 req->qtcb->header.port_handle = wka_port->handle;
1734
1735 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1736 retval = zfcp_fsf_req_send(req);
1737 if (retval)
1738 zfcp_fsf_req_free(req);
1739out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001740 spin_unlock_bh(&qdio->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001741 return retval;
1742}
1743
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001744static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001746 struct zfcp_port *port = req->data;
1747 struct fsf_qtcb_header *header = &req->qtcb->header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 struct zfcp_unit *unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001750 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Christof Schmitta5b11dd2009-03-02 13:08:54 +01001751 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 switch (header->fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001755 zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001756 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001759 zfcp_fsf_access_denied_port(req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 case FSF_PORT_BOXED:
Christof Schmitt5c815d12008-03-10 16:18:54 +01001762 /* can't use generic zfcp_erp_modify_port_status because
1763 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
1764 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Swen Schilligecf0c772009-11-24 16:53:58 +01001765 read_lock(&port->unit_list_lock);
1766 list_for_each_entry(unit, &port->unit_list, list)
Christof Schmitt5c815d12008-03-10 16:18:54 +01001767 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1768 &unit->status);
Swen Schilligecf0c772009-11-24 16:53:58 +01001769 read_unlock(&port->unit_list_lock);
Swen Schilligdfb3cf02009-07-13 15:06:02 +02001770 zfcp_erp_port_boxed(port, "fscpph2", req);
1771 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1772 ZFCP_STATUS_FSFREQ_RETRY;
1773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 switch (header->fsf_status_qual.word[0]) {
1777 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001778 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001780 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 }
1783 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 /* can't use generic zfcp_erp_modify_port_status because
1786 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
1787 */
1788 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Swen Schilligecf0c772009-11-24 16:53:58 +01001789 read_lock(&port->unit_list_lock);
1790 list_for_each_entry(unit, &port->unit_list, list)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001791 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1792 &unit->status);
Swen Schilligecf0c772009-11-24 16:53:58 +01001793 read_unlock(&port->unit_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796}
1797
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001798/**
1799 * zfcp_fsf_close_physical_port - close physical port
1800 * @erp_action: pointer to struct zfcp_erp_action
1801 * Returns: 0 on success
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001803int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001805 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02001806 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001807 struct zfcp_fsf_req *req;
1808 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
Swen Schillig564e1c82009-08-18 15:43:19 +02001810 spin_lock_bh(&qdio->req_q_lock);
1811 if (zfcp_fsf_req_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
Swen Schillig564e1c82009-08-18 15:43:19 +02001814 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1815 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001816
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001817 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001818 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 goto out;
1820 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001821
Swen Schillig09a46c62009-08-18 15:43:16 +02001822 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001823 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001824 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1825 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1826
1827 req->data = erp_action->port;
1828 req->qtcb->header.port_handle = erp_action->port->handle;
1829 req->erp_action = erp_action;
1830 req->handler = zfcp_fsf_close_physical_port_handler;
1831 erp_action->fsf_req = req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001832
Christof Schmitt287ac012008-07-02 10:56:40 +02001833 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001834 retval = zfcp_fsf_req_send(req);
1835 if (retval) {
1836 zfcp_fsf_req_free(req);
1837 erp_action->fsf_req = NULL;
1838 }
1839out:
Swen Schillig564e1c82009-08-18 15:43:19 +02001840 spin_unlock_bh(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return retval;
1842}
1843
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001844static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001846 struct zfcp_adapter *adapter = req->adapter;
1847 struct zfcp_unit *unit = req->data;
1848 struct fsf_qtcb_header *header = &req->qtcb->header;
1849 struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1850 struct fsf_queue_designator *queue_designator =
1851 &header->fsf_status_qual.fsf_queue_designator;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001852 int exclusive, readwrite;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001854 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001855 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Heiko Carstensb64ddf92007-05-08 11:19:57 +02001858 ZFCP_STATUS_COMMON_ACCESS_BOXED |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 ZFCP_STATUS_UNIT_SHARED |
1860 ZFCP_STATUS_UNIT_READONLY,
1861 &unit->status);
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 switch (header->fsf_status) {
1864
1865 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001866 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001867 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 case FSF_LUN_ALREADY_OPEN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001871 zfcp_fsf_access_denied_unit(req, unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
Christof Schmitt553448f2008-06-10 18:20:58 +02001873 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001876 zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001877 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1878 ZFCP_STATUS_FSFREQ_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 case FSF_LUN_SHARING_VIOLATION:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001881 if (header->fsf_status_qual.word[0])
Christof Schmitt553448f2008-06-10 18:20:58 +02001882 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001883 "LUN 0x%Lx on port 0x%Lx is already in "
1884 "use by CSS%d, MIF Image ID %x\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001885 (unsigned long long)unit->fcp_lun,
1886 (unsigned long long)unit->port->wwpn,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001887 queue_designator->cssid,
1888 queue_designator->hla);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001889 else
Christof Schmitt553448f2008-06-10 18:20:58 +02001890 zfcp_act_eval_err(adapter,
1891 header->fsf_status_qual.word[2]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001892 zfcp_erp_unit_access_denied(unit, "fsouh_3", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1894 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001895 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001898 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001899 "No handle is available for LUN "
1900 "0x%016Lx on port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001901 (unsigned long long)unit->fcp_lun,
1902 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001903 zfcp_erp_unit_failed(unit, "fsouh_4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001904 /* fall through */
1905 case FSF_INVALID_COMMAND_OPTION:
1906 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 switch (header->fsf_status_qual.word[0]) {
1910 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schillig6f53a2d2009-08-18 15:43:23 +02001911 zfcp_fc_test_link(unit->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001912 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001914 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 }
1917 break;
1918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 unit->handle = header->lun_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001922
1923 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1924 (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
Christof Schmitt6fcf41d2009-05-15 13:18:21 +02001925 !zfcp_ccw_priv_sch(adapter)) {
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001926 exclusive = (bottom->lun_access_info &
1927 FSF_UNIT_ACCESS_EXCLUSIVE);
1928 readwrite = (bottom->lun_access_info &
1929 FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 if (!exclusive)
1932 atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
1933 &unit->status);
1934
1935 if (!readwrite) {
1936 atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
1937 &unit->status);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001938 dev_info(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001939 "SCSI device at LUN 0x%016Lx on port "
1940 "0x%016Lx opened read-only\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001941 (unsigned long long)unit->fcp_lun,
1942 (unsigned long long)unit->port->wwpn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
1944
1945 if (exclusive && !readwrite) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001946 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001947 "Exclusive read-only access not "
1948 "supported (unit 0x%016Lx, "
1949 "port 0x%016Lx)\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001950 (unsigned long long)unit->fcp_lun,
1951 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001952 zfcp_erp_unit_failed(unit, "fsouh_5", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001953 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001954 zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 } else if (!exclusive && readwrite) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001956 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001957 "Shared read-write access not "
1958 "supported (unit 0x%016Lx, port "
Christof Schmitt27c3f0a2008-12-19 16:56:52 +01001959 "0x%016Lx)\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001960 (unsigned long long)unit->fcp_lun,
1961 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001962 zfcp_erp_unit_failed(unit, "fsouh_7", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001963 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001964 zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969}
1970
1971/**
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001972 * zfcp_fsf_open_unit - open unit
1973 * @erp_action: pointer to struct zfcp_erp_action
1974 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001976int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001978 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001979 struct zfcp_adapter *adapter = erp_action->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +02001980 struct zfcp_qdio *qdio = adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001981 struct zfcp_fsf_req *req;
1982 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
Swen Schillig564e1c82009-08-18 15:43:19 +02001984 spin_lock_bh(&qdio->req_q_lock);
1985 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001986 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Swen Schillig564e1c82009-08-18 15:43:19 +02001988 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
Swen Schilliga4623c42009-08-18 15:43:15 +02001989 adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001990
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001991 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001992 retval = PTR_ERR(req);
1993 goto out;
Christof Schmittba172422007-12-20 12:30:26 +01001994 }
1995
Swen Schillig09a46c62009-08-18 15:43:16 +02001996 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02001997 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001998 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1999 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002001 req->qtcb->header.port_handle = erp_action->port->handle;
2002 req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
2003 req->handler = zfcp_fsf_open_unit_handler;
2004 req->data = erp_action->unit;
2005 req->erp_action = erp_action;
2006 erp_action->fsf_req = req;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002007
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002008 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
2009 req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Christof Schmitt287ac012008-07-02 10:56:40 +02002011 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002012 retval = zfcp_fsf_req_send(req);
2013 if (retval) {
2014 zfcp_fsf_req_free(req);
2015 erp_action->fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002017out:
Swen Schillig564e1c82009-08-18 15:43:19 +02002018 spin_unlock_bh(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return retval;
2020}
2021
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002022static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002024 struct zfcp_unit *unit = req->data;
2025
2026 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02002027 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002028
2029 switch (req->qtcb->header.fsf_status) {
2030 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002031 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002032 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2033 break;
2034 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002035 zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002036 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2037 break;
2038 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002039 zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002040 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2041 ZFCP_STATUS_FSFREQ_RETRY;
2042 break;
2043 case FSF_ADAPTER_STATUS_AVAILABLE:
2044 switch (req->qtcb->header.fsf_status_qual.word[0]) {
2045 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schillig6f53a2d2009-08-18 15:43:23 +02002046 zfcp_fc_test_link(unit->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002047 /* fall through */
2048 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
2049 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2050 break;
2051 }
2052 break;
2053 case FSF_GOOD:
2054 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
2055 break;
2056 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002057}
2058
2059/**
2060 * zfcp_fsf_close_unit - close zfcp unit
2061 * @erp_action: pointer to struct zfcp_unit
2062 * Returns: 0 on success, error otherwise
2063 */
2064int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
2065{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002066 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02002067 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002068 struct zfcp_fsf_req *req;
2069 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Swen Schillig564e1c82009-08-18 15:43:19 +02002071 spin_lock_bh(&qdio->req_q_lock);
2072 if (zfcp_fsf_req_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02002074
Swen Schillig564e1c82009-08-18 15:43:19 +02002075 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
2076 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02002077
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002078 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002079 retval = PTR_ERR(req);
2080 goto out;
2081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
Swen Schillig09a46c62009-08-18 15:43:16 +02002083 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig564e1c82009-08-18 15:43:19 +02002084 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002085 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2087
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002088 req->qtcb->header.port_handle = erp_action->port->handle;
2089 req->qtcb->header.lun_handle = erp_action->unit->handle;
2090 req->handler = zfcp_fsf_close_unit_handler;
2091 req->data = erp_action->unit;
2092 req->erp_action = erp_action;
2093 erp_action->fsf_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Christof Schmitt287ac012008-07-02 10:56:40 +02002095 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002096 retval = zfcp_fsf_req_send(req);
2097 if (retval) {
2098 zfcp_fsf_req_free(req);
2099 erp_action->fsf_req = NULL;
2100 }
2101out:
Swen Schillig564e1c82009-08-18 15:43:19 +02002102 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002103 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104}
2105
Christof Schmittc9615852008-05-06 11:00:05 +02002106static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2107{
2108 lat_rec->sum += lat;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002109 lat_rec->min = min(lat_rec->min, lat);
2110 lat_rec->max = max(lat_rec->max, lat);
Christof Schmittc9615852008-05-06 11:00:05 +02002111}
2112
Christof Schmittd9742b42009-11-24 16:54:03 +01002113static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
Christof Schmittc9615852008-05-06 11:00:05 +02002114{
Christof Schmittd9742b42009-11-24 16:54:03 +01002115 struct fsf_qual_latency_info *lat_in;
2116 struct latency_cont *lat = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002117 struct zfcp_unit *unit = req->unit;
Christof Schmittd9742b42009-11-24 16:54:03 +01002118 struct zfcp_blk_drv_data blktrc;
2119 int ticks = req->adapter->timer_ticks;
Christof Schmittc9615852008-05-06 11:00:05 +02002120
Christof Schmittd9742b42009-11-24 16:54:03 +01002121 lat_in = &req->qtcb->prefix.prot_status_qual.latency_info;
Christof Schmittc9615852008-05-06 11:00:05 +02002122
Christof Schmittd9742b42009-11-24 16:54:03 +01002123 blktrc.flags = 0;
2124 blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
2125 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
2126 blktrc.flags |= ZFCP_BLK_REQ_ERROR;
2127 blktrc.inb_usage = req->queue_req.qdio_inb_usage;
2128 blktrc.outb_usage = req->queue_req.qdio_outb_usage;
2129
2130 if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
2131 blktrc.flags |= ZFCP_BLK_LAT_VALID;
2132 blktrc.channel_lat = lat_in->channel_lat * ticks;
2133 blktrc.fabric_lat = lat_in->fabric_lat * ticks;
2134
2135 switch (req->qtcb->bottom.io.data_direction) {
2136 case FSF_DATADIR_READ:
2137 lat = &unit->latencies.read;
2138 break;
2139 case FSF_DATADIR_WRITE:
2140 lat = &unit->latencies.write;
2141 break;
2142 case FSF_DATADIR_CMND:
2143 lat = &unit->latencies.cmd;
2144 break;
2145 }
2146
2147 if (lat) {
2148 spin_lock(&unit->latencies.lock);
2149 zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat);
2150 zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat);
2151 lat->counter++;
2152 spin_unlock(&unit->latencies.lock);
2153 }
Christof Schmittc9615852008-05-06 11:00:05 +02002154 }
2155
Christof Schmittd9742b42009-11-24 16:54:03 +01002156 blk_add_driver_data(scsi->request->q, scsi->request, &blktrc,
2157 sizeof(blktrc));
Christof Schmittc9615852008-05-06 11:00:05 +02002158}
2159
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002160static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161{
Swen Schillig0ac55aa2008-11-26 18:07:39 +01002162 struct scsi_cmnd *scpnt;
Christof Schmitt4318e082009-11-24 16:54:08 +01002163 struct fcp_resp_with_ext *fcp_rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002166 read_lock_irqsave(&req->adapter->abort_lock, flags);
2167
Swen Schillig0ac55aa2008-11-26 18:07:39 +01002168 scpnt = req->data;
2169 if (unlikely(!scpnt)) {
2170 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
2171 return;
2172 }
2173
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002174 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
Martin Petermannfeac6a02008-07-02 10:56:35 +02002175 set_host_byte(scpnt, DID_SOFT_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 goto skip_fsfstatus;
2177 }
2178
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002179 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
Martin Petermannfeac6a02008-07-02 10:56:35 +02002180 set_host_byte(scpnt, DID_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 goto skip_fsfstatus;
2182 }
2183
Christof Schmitt4318e082009-11-24 16:54:08 +01002184 fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
2185 zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
Christof Schmittd9742b42009-11-24 16:54:03 +01002187 zfcp_fsf_req_trace(req, scpnt);
Stefan Raspl0997f1c2008-10-16 08:23:39 +02002188
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002189skip_fsfstatus:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002190 if (scpnt->result != 0)
Swen Schillig57717102009-08-18 15:43:21 +02002191 zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002192 else if (scpnt->retries > 0)
Swen Schillig57717102009-08-18 15:43:21 +02002193 zfcp_dbf_scsi_result("retr", 4, req->adapter->dbf, scpnt, req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002194 else
Swen Schillig57717102009-08-18 15:43:21 +02002195 zfcp_dbf_scsi_result("norm", 6, req->adapter->dbf, scpnt, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 scpnt->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 (scpnt->scsi_done) (scpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 /*
2200 * We must hold this lock until scsi_done has been called.
2201 * Otherwise we may call scsi_done after abort regarding this
2202 * command has completed.
2203 * Note: scsi_done must not block!
2204 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002205 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206}
2207
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002208static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209{
Christof Schmitt4318e082009-11-24 16:54:08 +01002210 struct fcp_resp_with_ext *fcp_rsp;
2211 struct fcp_resp_rsp_info *rsp_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Christof Schmitt4318e082009-11-24 16:54:08 +01002213 fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
2214 rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
2215
2216 if ((rsp_info->rsp_code != FCP_TMF_CMPL) ||
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002217 (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2218 req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219}
2220
2221
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002222static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2223{
2224 struct zfcp_unit *unit;
2225 struct fsf_qtcb_header *header = &req->qtcb->header;
2226
2227 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2228 unit = req->data;
2229 else
2230 unit = req->unit;
2231
2232 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
2233 goto skip_fsfstatus;
2234
2235 switch (header->fsf_status) {
2236 case FSF_HANDLE_MISMATCH:
2237 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002238 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002239 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2240 break;
2241 case FSF_FCPLUN_NOT_VALID:
2242 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002243 zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002244 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2245 break;
2246 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2247 zfcp_fsf_class_not_supp(req);
2248 break;
2249 case FSF_ACCESS_DENIED:
2250 zfcp_fsf_access_denied_unit(req, unit);
2251 break;
2252 case FSF_DIRECTION_INDICATOR_NOT_VALID:
2253 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002254 "Incorrect direction %d, unit 0x%016Lx on port "
2255 "0x%016Lx closed\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002256 req->qtcb->bottom.io.data_direction,
Swen Schillig7ba58c92008-10-01 12:42:18 +02002257 (unsigned long long)unit->fcp_lun,
2258 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002259 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3",
2260 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002261 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2262 break;
2263 case FSF_CMND_LENGTH_NOT_VALID:
2264 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002265 "Incorrect CDB length %d, unit 0x%016Lx on "
2266 "port 0x%016Lx closed\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002267 req->qtcb->bottom.io.fcp_cmnd_length,
Swen Schillig7ba58c92008-10-01 12:42:18 +02002268 (unsigned long long)unit->fcp_lun,
2269 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002270 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4",
2271 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002272 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2273 break;
2274 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002275 zfcp_erp_port_boxed(unit->port, "fssfch5", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002276 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2277 ZFCP_STATUS_FSFREQ_RETRY;
2278 break;
2279 case FSF_LUN_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002280 zfcp_erp_unit_boxed(unit, "fssfch6", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002281 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2282 ZFCP_STATUS_FSFREQ_RETRY;
2283 break;
2284 case FSF_ADAPTER_STATUS_AVAILABLE:
2285 if (header->fsf_status_qual.word[0] ==
2286 FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
Swen Schillig6f53a2d2009-08-18 15:43:23 +02002287 zfcp_fc_test_link(unit->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002288 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2289 break;
2290 }
2291skip_fsfstatus:
2292 if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2293 zfcp_fsf_send_fcp_ctm_handler(req);
2294 else {
2295 zfcp_fsf_send_fcp_command_task_handler(req);
2296 req->unit = NULL;
Swen Schilligf3450c72009-11-24 16:53:59 +01002297 put_device(&unit->sysfs_device);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002298 }
2299}
2300
2301/**
2302 * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002303 * @unit: unit where command is sent to
2304 * @scsi_cmnd: scsi command to be sent
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002305 */
Christof Schmitt63caf362009-03-02 13:09:00 +01002306int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
2307 struct scsi_cmnd *scsi_cmnd)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002308{
2309 struct zfcp_fsf_req *req;
Christof Schmitt4318e082009-11-24 16:54:08 +01002310 struct fcp_cmnd *fcp_cmnd;
Christof Schmittbc90c862009-05-15 13:18:17 +02002311 unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002312 int real_bytes, retval = -EIO;
Christof Schmitt63caf362009-03-02 13:09:00 +01002313 struct zfcp_adapter *adapter = unit->port->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +02002314 struct zfcp_qdio *qdio = adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002315
2316 if (unlikely(!(atomic_read(&unit->status) &
2317 ZFCP_STATUS_COMMON_UNBLOCKED)))
2318 return -EBUSY;
2319
Swen Schillig564e1c82009-08-18 15:43:19 +02002320 spin_lock(&qdio->req_q_lock);
2321 if (atomic_read(&qdio->req_q.count) <= 0) {
2322 atomic_inc(&qdio->req_q_full);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002323 goto out;
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01002324 }
Swen Schillig09a46c62009-08-18 15:43:16 +02002325
Swen Schillig564e1c82009-08-18 15:43:19 +02002326 req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
Swen Schilliga4623c42009-08-18 15:43:15 +02002327 adapter->pool.scsi_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02002328
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002329 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002330 retval = PTR_ERR(req);
2331 goto out;
2332 }
2333
Swen Schillig09a46c62009-08-18 15:43:16 +02002334 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schilligf3450c72009-11-24 16:53:59 +01002335 get_device(&unit->sysfs_device);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002336 req->unit = unit;
2337 req->data = scsi_cmnd;
2338 req->handler = zfcp_fsf_send_fcp_command_handler;
2339 req->qtcb->header.lun_handle = unit->handle;
2340 req->qtcb->header.port_handle = unit->port->handle;
2341 req->qtcb->bottom.io.service_class = FSF_CLASS_3;
Christof Schmitt4318e082009-11-24 16:54:08 +01002342 req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002343
2344 scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2345
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002346 /*
2347 * set depending on data direction:
2348 * data direction bits in SBALE (SB Type)
2349 * data direction bits in QTCB
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002350 */
2351 switch (scsi_cmnd->sc_data_direction) {
2352 case DMA_NONE:
2353 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002354 break;
2355 case DMA_FROM_DEVICE:
2356 req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002357 break;
2358 case DMA_TO_DEVICE:
2359 req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2360 sbtype = SBAL_FLAGS0_TYPE_WRITE;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002361 break;
2362 case DMA_BIDIRECTIONAL:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002363 goto failed_scsi_cmnd;
2364 }
2365
Christof Schmitt4318e082009-11-24 16:54:08 +01002366 fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
2367 zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002368
Swen Schillig564e1c82009-08-18 15:43:19 +02002369 real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002370 scsi_sglist(scsi_cmnd),
2371 FSF_MAX_SBALS_PER_REQ);
2372 if (unlikely(real_bytes < 0)) {
Swen Schillig42428f72009-08-18 15:43:18 +02002373 if (req->queue_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002374 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002375 "Oversize data package, unit 0x%016Lx "
2376 "on port 0x%016Lx closed\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02002377 (unsigned long long)unit->fcp_lun,
2378 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002379 zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002380 retval = -EINVAL;
2381 }
2382 goto failed_scsi_cmnd;
2383 }
2384
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002385 retval = zfcp_fsf_req_send(req);
2386 if (unlikely(retval))
2387 goto failed_scsi_cmnd;
2388
2389 goto out;
2390
2391failed_scsi_cmnd:
Swen Schilligf3450c72009-11-24 16:53:59 +01002392 put_device(&unit->sysfs_device);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002393 zfcp_fsf_req_free(req);
2394 scsi_cmnd->host_scribble = NULL;
2395out:
Swen Schillig564e1c82009-08-18 15:43:19 +02002396 spin_unlock(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002397 return retval;
2398}
2399
2400/**
2401 * zfcp_fsf_send_fcp_ctm - send SCSI task management command
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002402 * @unit: pointer to struct zfcp_unit
2403 * @tm_flags: unsigned byte for task management flags
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002404 * Returns: on success pointer to struct fsf_req, NULL otherwise
2405 */
Christof Schmitt63caf362009-03-02 13:09:00 +01002406struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002407{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002408 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002409 struct zfcp_fsf_req *req = NULL;
Christof Schmitt4318e082009-11-24 16:54:08 +01002410 struct fcp_cmnd *fcp_cmnd;
Swen Schillig564e1c82009-08-18 15:43:19 +02002411 struct zfcp_qdio *qdio = unit->port->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002412
2413 if (unlikely(!(atomic_read(&unit->status) &
2414 ZFCP_STATUS_COMMON_UNBLOCKED)))
2415 return NULL;
2416
Swen Schillig564e1c82009-08-18 15:43:19 +02002417 spin_lock_bh(&qdio->req_q_lock);
2418 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002419 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02002420
Swen Schillig564e1c82009-08-18 15:43:19 +02002421 req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
2422 qdio->adapter->pool.scsi_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02002423
Swen Schillig633528c2008-11-26 18:07:37 +01002424 if (IS_ERR(req)) {
2425 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002426 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +01002427 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002428
2429 req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2430 req->data = unit;
2431 req->handler = zfcp_fsf_send_fcp_command_handler;
2432 req->qtcb->header.lun_handle = unit->handle;
2433 req->qtcb->header.port_handle = unit->port->handle;
2434 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2435 req->qtcb->bottom.io.service_class = FSF_CLASS_3;
Christof Schmitt4318e082009-11-24 16:54:08 +01002436 req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002437
Swen Schillig564e1c82009-08-18 15:43:19 +02002438 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002439 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2440 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2441
Christof Schmitt4318e082009-11-24 16:54:08 +01002442 fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
2443 zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002444
2445 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2446 if (!zfcp_fsf_req_send(req))
2447 goto out;
2448
2449 zfcp_fsf_req_free(req);
2450 req = NULL;
2451out:
Swen Schillig564e1c82009-08-18 15:43:19 +02002452 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002453 return req;
2454}
2455
2456static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2457{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002458}
2459
2460/**
2461 * zfcp_fsf_control_file - control file upload/download
2462 * @adapter: pointer to struct zfcp_adapter
2463 * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2464 * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 */
Christof Schmitt45633fd2008-06-10 18:20:55 +02002466struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2467 struct zfcp_fsf_cfdc *fsf_cfdc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002469 struct qdio_buffer_element *sbale;
Swen Schillig564e1c82009-08-18 15:43:19 +02002470 struct zfcp_qdio *qdio = adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002471 struct zfcp_fsf_req *req = NULL;
2472 struct fsf_qtcb_bottom_support *bottom;
2473 int direction, retval = -EIO, bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
Christof Schmitt45633fd2008-06-10 18:20:55 +02002475 if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2476 return ERR_PTR(-EOPNOTSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
Christof Schmitt45633fd2008-06-10 18:20:55 +02002478 switch (fsf_cfdc->command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2480 direction = SBAL_FLAGS0_TYPE_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 case FSF_QTCB_UPLOAD_CONTROL_FILE:
2483 direction = SBAL_FLAGS0_TYPE_READ;
2484 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 default:
Christof Schmitt45633fd2008-06-10 18:20:55 +02002486 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
2488
Swen Schillig564e1c82009-08-18 15:43:19 +02002489 spin_lock_bh(&qdio->req_q_lock);
2490 if (zfcp_fsf_req_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002491 goto out;
2492
Swen Schillig564e1c82009-08-18 15:43:19 +02002493 req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002494 if (IS_ERR(req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 retval = -EPERM;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002496 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 }
2498
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002499 req->handler = zfcp_fsf_control_file_handler;
2500
Swen Schillig564e1c82009-08-18 15:43:19 +02002501 sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 sbale[0].flags |= direction;
2503
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002504 bottom = &req->qtcb->bottom.support;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
Christof Schmitt45633fd2008-06-10 18:20:55 +02002506 bottom->option = fsf_cfdc->option;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
Swen Schillig564e1c82009-08-18 15:43:19 +02002508 bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req,
2509 direction, fsf_cfdc->sg,
2510 FSF_MAX_SBALS_PER_REQ);
Christof Schmitt45633fd2008-06-10 18:20:55 +02002511 if (bytes != ZFCP_CFDC_MAX_SIZE) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002512 zfcp_fsf_req_free(req);
2513 goto out;
Christof Schmitt45633fd2008-06-10 18:20:55 +02002514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002516 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2517 retval = zfcp_fsf_req_send(req);
2518out:
Swen Schillig564e1c82009-08-18 15:43:19 +02002519 spin_unlock_bh(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002520
2521 if (!retval) {
Swen Schillig058b8642009-08-18 15:43:14 +02002522 wait_for_completion(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002523 return req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
Christof Schmitt45633fd2008-06-10 18:20:55 +02002525 return ERR_PTR(retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526}
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002527
2528/**
2529 * zfcp_fsf_reqid_check - validate req_id contained in SBAL returned by QDIO
2530 * @adapter: pointer to struct zfcp_adapter
2531 * @sbal_idx: response queue index of SBAL to be processed
2532 */
Swen Schillig564e1c82009-08-18 15:43:19 +02002533void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002534{
Swen Schillig564e1c82009-08-18 15:43:19 +02002535 struct zfcp_adapter *adapter = qdio->adapter;
2536 struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002537 struct qdio_buffer_element *sbale;
2538 struct zfcp_fsf_req *fsf_req;
2539 unsigned long flags, req_id;
2540 int idx;
2541
2542 for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) {
2543
2544 sbale = &sbal->element[idx];
2545 req_id = (unsigned long) sbale->addr;
2546 spin_lock_irqsave(&adapter->req_list_lock, flags);
2547 fsf_req = zfcp_reqlist_find(adapter, req_id);
2548
2549 if (!fsf_req)
2550 /*
2551 * Unknown request means that we have potentially memory
2552 * corruption and must stop the machine immediately.
2553 */
2554 panic("error: unknown req_id (%lx) on adapter %s.\n",
2555 req_id, dev_name(&adapter->ccw_device->dev));
2556
2557 list_del(&fsf_req->list);
2558 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
2559
Swen Schillig42428f72009-08-18 15:43:18 +02002560 fsf_req->queue_req.sbal_response = sbal_idx;
2561 fsf_req->queue_req.qdio_inb_usage =
Swen Schillig564e1c82009-08-18 15:43:19 +02002562 atomic_read(&qdio->resp_q.count);
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002563 zfcp_fsf_req_complete(fsf_req);
2564
2565 if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
2566 break;
2567 }
2568}