ses.c revision 8c3adc796f32fa4878ec843f8960717ba377e024
19927c68864e9c39cc317b4f559309ba29e642168James Bottomley/* 29927c68864e9c39cc317b4f559309ba29e642168James Bottomley * SCSI Enclosure Services 39927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 49927c68864e9c39cc317b4f559309ba29e642168James Bottomley * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 59927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 69927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 79927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 89927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is free software; you can redistribute it and/or 99927c68864e9c39cc317b4f559309ba29e642168James Bottomley** modify it under the terms of the GNU General Public License 109927c68864e9c39cc317b4f559309ba29e642168James Bottomley** version 2 as published by the Free Software Foundation. 119927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 129927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is distributed in the hope that it will be useful, 139927c68864e9c39cc317b4f559309ba29e642168James Bottomley** but WITHOUT ANY WARRANTY; without even the implied warranty of 149927c68864e9c39cc317b4f559309ba29e642168James Bottomley** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159927c68864e9c39cc317b4f559309ba29e642168James Bottomley** GNU General Public License for more details. 169927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 179927c68864e9c39cc317b4f559309ba29e642168James Bottomley** You should have received a copy of the GNU General Public License 189927c68864e9c39cc317b4f559309ba29e642168James Bottomley** along with this program; if not, write to the Free Software 199927c68864e9c39cc317b4f559309ba29e642168James Bottomley** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 209927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 219927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 229927c68864e9c39cc317b4f559309ba29e642168James Bottomley*/ 239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 259927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/module.h> 269927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/kernel.h> 279927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/enclosure.h> 289927c68864e9c39cc317b4f559309ba29e642168James Bottomley 299927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi.h> 309927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_cmnd.h> 319927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_dbg.h> 329927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_device.h> 339927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_driver.h> 349927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_host.h> 359927c68864e9c39cc317b4f559309ba29e642168James Bottomley 369927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_device { 37691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page1; 388c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *page1_types; 39691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page2; 40691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page10; 419927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page1_len; 428c3adc796f32fa4878ec843f8960717ba377e024James Bottomley short page1_num_types; 439927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page2_len; 449927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page10_len; 459927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 479927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_component { 489927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 499927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 509927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 519927c68864e9c39cc317b4f559309ba29e642168James Bottomley 529927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_probe(struct device *dev) 539927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 549927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev = to_scsi_device(dev); 559927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENODEV; 569927c68864e9c39cc317b4f559309ba29e642168James Bottomley 579927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 589927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out; 599927c68864e9c39cc317b4f559309ba29e642168James Bottomley 609927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = 0; 619927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); 629927c68864e9c39cc317b4f559309ba29e642168James Bottomley 639927c68864e9c39cc317b4f559309ba29e642168James Bottomley out: 649927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 659927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 669927c68864e9c39cc317b4f559309ba29e642168James Bottomley 67c95e62ce8905aab62fed224eaaa9b8558a0ef652Matthew Wilcox#define SES_TIMEOUT (30 * HZ) 689927c68864e9c39cc317b4f559309ba29e642168James Bottomley#define SES_RETRIES 3 699927c68864e9c39cc317b4f559309ba29e642168James Bottomley 709927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_recv_diag(struct scsi_device *sdev, int page_code, 719927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 729927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 73691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 749927c68864e9c39cc317b4f559309ba29e642168James Bottomley RECEIVE_DIAGNOSTIC, 759927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1, /* Set PCV bit */ 769927c68864e9c39cc317b4f559309ba29e642168James Bottomley page_code, 779927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 789927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 799927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 809927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 819927c68864e9c39cc317b4f559309ba29e642168James Bottomley 829927c68864e9c39cc317b4f559309ba29e642168James Bottomley return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, 83f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 849927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 859927c68864e9c39cc317b4f559309ba29e642168James Bottomley 869927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_send_diag(struct scsi_device *sdev, int page_code, 879927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 889927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 899927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 91691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 929927c68864e9c39cc317b4f559309ba29e642168James Bottomley SEND_DIAGNOSTIC, 939927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0x10, /* Set PF bit */ 949927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0, 959927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 969927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 979927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 989927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 999927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1009927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, 101f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 1029927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 1039927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", 1049927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 1059927c68864e9c39cc317b4f559309ba29e642168James Bottomley return result; 1069927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1079927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1089927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_page2_descriptor(struct enclosure_device *edev, 1099927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 110691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc) 1119927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1129927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 113ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1149927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 1158c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *type_ptr = ses_dev->page1_types; 116691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1179927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1189927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* Clear everything */ 1199927c68864e9c39cc317b4f559309ba29e642168James Bottomley memset(desc_ptr, 0, ses_dev->page2_len - 8); 1208c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { 1219927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1229927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1239927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1249927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1259927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1269927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) { 1279927c68864e9c39cc317b4f559309ba29e642168James Bottomley memcpy(desc_ptr, desc, 4); 1289927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* set select */ 1299927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] |= 0x80; 1309927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* clear reserved, just in case */ 1319927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] &= 0xf0; 1329927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1339927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1349927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1359927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1369927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1379927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1389927c68864e9c39cc317b4f559309ba29e642168James Bottomley 139691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lustatic unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, 1409927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1419927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1429927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 143ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1449927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 1458c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *type_ptr = ses_dev->page1_types; 146691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1479927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1489927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1499927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1508c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { 1519927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1529927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1539927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1549927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1559927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1569927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) 1579927c68864e9c39cc317b4f559309ba29e642168James Bottomley return desc_ptr; 1589927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1599927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1609927c68864e9c39cc317b4f559309ba29e642168James Bottomley return NULL; 1619927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1629927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1639927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_fault(struct enclosure_device *edev, 1649927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1659927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 166691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 1679927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1689927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 169691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 170691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->fault = (desc[3] & 0x60) >> 4; 1719927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1729927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1739927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_fault(struct enclosure_device *edev, 1749927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 1759927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 1769927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 177691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 1789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1799927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 1809927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 1819927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 1829927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1839927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 1849927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x02; 1859927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1869927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 1879927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 1889927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 1899927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1919927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 1929927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1939927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1949927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_status(struct enclosure_device *edev, 1959927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1969927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 197691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 1989927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1999927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 200691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 201691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->status = (desc[0] & 0x0f); 2029927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2049927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_locate(struct enclosure_device *edev, 2059927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 2069927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 207691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 2089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2099927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 210691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 211691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->locate = (desc[2] & 0x02) ? 1 : 0; 2129927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2139927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2149927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_locate(struct enclosure_device *edev, 2159927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2169927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2179927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 218691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2199927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2209927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2219927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2229927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2239927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2249927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2259927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x02; 2269927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2279927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2289927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2299927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2309927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2319927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2329927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2339927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2349927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_active(struct enclosure_device *edev, 2359927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2369927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2379927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 238691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2399927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2409927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2419927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2429927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2439927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 0; 2449927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2459927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2469927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x80; 2479927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 1; 2489927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2499927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2509927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2519927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2529927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2539927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2549927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2559927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2569927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct enclosure_component_callbacks ses_enclosure_callbacks = { 2579927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_fault = ses_get_fault, 2589927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_fault = ses_set_fault, 2599927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_status = ses_get_status, 2609927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_locate = ses_get_locate, 2619927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_locate = ses_set_locate, 2629927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_active = ses_set_active, 2639927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2649927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2659927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_host_edev { 2669927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct Scsi_Host *shost; 2679927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 2689927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2699927c68864e9c39cc317b4f559309ba29e642168James Bottomley 270e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#if 0 2719927c68864e9c39cc317b4f559309ba29e642168James Bottomleyint ses_match_host(struct enclosure_device *edev, void *data) 2729927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2739927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_host_edev *sed = data; 2749927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev; 2759927c68864e9c39cc317b4f559309ba29e642168James Bottomley 276ee959b00c335d7780136c5abda37809191fe52c3Tony Jones if (!scsi_is_sdev_device(edev->edev.parent)) 2779927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 279ee959b00c335d7780136c5abda37809191fe52c3Tony Jones sdev = to_scsi_device(edev->edev.parent); 2809927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2819927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->host != sed->shost) 2829927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2839927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2849927c68864e9c39cc317b4f559309ba29e642168James Bottomley sed->edev = edev; 2859927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 2869927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 287e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#endif /* 0 */ 2889927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2899927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_process_descriptor(struct enclosure_component *ecomp, 2909927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc) 2919927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2929927c68864e9c39cc317b4f559309ba29e642168James Bottomley int eip = desc[0] & 0x10; 2939927c68864e9c39cc317b4f559309ba29e642168James Bottomley int invalid = desc[0] & 0x80; 2949927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] & 0x0f; 2959927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr = 0; 2969927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp = ecomp->scratch; 2979927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *d; 2989927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2999927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->desc = desc; 3009927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3019927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (invalid) 3029927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 3039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3049927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (proto) { 3059927c68864e9c39cc317b4f559309ba29e642168James Bottomley case SCSI_PROTOCOL_SAS: 3069927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (eip) 3079927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 8; 3089927c68864e9c39cc317b4f559309ba29e642168James Bottomley else 3099927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 4; 3109927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* only take the phy0 addr */ 3119927c68864e9c39cc317b4f559309ba29e642168James Bottomley addr = (u64)d[12] << 56 | 3129927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[13] << 48 | 3139927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[14] << 40 | 3149927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[15] << 32 | 3159927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[16] << 24 | 3169927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[17] << 16 | 3179927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[18] << 8 | 3189927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[19]; 3199927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3209927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 3219927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* FIXME: Need to add more protocols than just SAS */ 3229927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3239927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3249927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->addr = addr; 3259927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3269927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3279927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct efd { 3289927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 3299927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct device *dev; 3309927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 3319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3329927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_enclosure_find_by_addr(struct enclosure_device *edev, 3339927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *data) 3349927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 3359927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd *efd = data; 3369927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i; 3379927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp; 3389927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3399927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev->component[0].scratch) 3409927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3419927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3429927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < edev->components; i++) { 3439927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp = edev->component[i].scratch; 3449927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (scomp->addr != efd->addr) 3459927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 3469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3479927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_add_device(edev, i, efd->dev); 3489927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 3499927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3509927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3519927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3529927c68864e9c39cc317b4f559309ba29e642168James Bottomley 35321fab1d0595eacf781705ec3509012a28f298245James Bottomley#define INIT_ALLOC_SIZE 32 35421fab1d0595eacf781705ec3509012a28f298245James Bottomley 35521fab1d0595eacf781705ec3509012a28f298245James Bottomleystatic void ses_enclosure_data_process(struct enclosure_device *edev, 35621fab1d0595eacf781705ec3509012a28f298245James Bottomley struct scsi_device *sdev, 35721fab1d0595eacf781705ec3509012a28f298245James Bottomley int create) 35821fab1d0595eacf781705ec3509012a28f298245James Bottomley{ 35921fab1d0595eacf781705ec3509012a28f298245James Bottomley u32 result; 36021fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; 36121fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, j, page7_len, len, components; 36221fab1d0595eacf781705ec3509012a28f298245James Bottomley struct ses_device *ses_dev = edev->scratch; 3638c3adc796f32fa4878ec843f8960717ba377e024James Bottomley int types = ses_dev->page1_num_types; 36421fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 36521fab1d0595eacf781705ec3509012a28f298245James Bottomley 36621fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!hdr_buf) 36721fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 36821fab1d0595eacf781705ec3509012a28f298245James Bottomley 36921fab1d0595eacf781705ec3509012a28f298245James Bottomley /* re-read page 10 */ 37021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (ses_dev->page10) 37121fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len); 37221fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Page 7 for the descriptors is optional */ 37321fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); 37421fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) 37521fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 37621fab1d0595eacf781705ec3509012a28f298245James Bottomley 37721fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 37821fab1d0595eacf781705ec3509012a28f298245James Bottomley /* add 1 for trailing '\0' we'll use */ 37921fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = kzalloc(len + 1, GFP_KERNEL); 38021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!buf) 38121fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 38221fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, buf, len); 38321fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) { 38421fab1d0595eacf781705ec3509012a28f298245James Bottomley simple_populate: 38521fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 38621fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = NULL; 38721fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 38821fab1d0595eacf781705ec3509012a28f298245James Bottomley len = 0; 38921fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = 0; 39021fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 39121fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = buf + 8; 39221fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 39321fab1d0595eacf781705ec3509012a28f298245James Bottomley /* skip past overall descriptor */ 39421fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len + 4; 39521fab1d0595eacf781705ec3509012a28f298245James Bottomley } 396877a55979c189c590e819a61cbbe2b7947875f17John Hughes if (ses_dev->page10) 397877a55979c189c590e819a61cbbe2b7947875f17John Hughes addl_desc_ptr = ses_dev->page10 + 8; 3988c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr = ses_dev->page1_types; 39921fab1d0595eacf781705ec3509012a28f298245James Bottomley components = 0; 40021fab1d0595eacf781705ec3509012a28f298245James Bottomley for (i = 0; i < types; i++, type_ptr += 4) { 40121fab1d0595eacf781705ec3509012a28f298245James Bottomley for (j = 0; j < type_ptr[1]; j++) { 40221fab1d0595eacf781705ec3509012a28f298245James Bottomley char *name = NULL; 40321fab1d0595eacf781705ec3509012a28f298245James Bottomley struct enclosure_component *ecomp; 40421fab1d0595eacf781705ec3509012a28f298245James Bottomley 40521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) { 40621fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr >= buf + page7_len) { 40721fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 40821fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 40921fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 41021fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += 4; 41121fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Add trailing zero - pushes into 41221fab1d0595eacf781705ec3509012a28f298245James Bottomley * reserved space */ 41321fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr[len] = '\0'; 41421fab1d0595eacf781705ec3509012a28f298245James Bottomley name = desc_ptr; 41521fab1d0595eacf781705ec3509012a28f298245James Bottomley } 41621fab1d0595eacf781705ec3509012a28f298245James Bottomley } 41721fab1d0595eacf781705ec3509012a28f298245James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 41821fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { 41921fab1d0595eacf781705ec3509012a28f298245James Bottomley 42021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (create) 42121fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = enclosure_component_register(edev, 42221fab1d0595eacf781705ec3509012a28f298245James Bottomley components++, 42321fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0], 42421fab1d0595eacf781705ec3509012a28f298245James Bottomley name); 42521fab1d0595eacf781705ec3509012a28f298245James Bottomley else 42621fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = &edev->component[components++]; 42721fab1d0595eacf781705ec3509012a28f298245James Bottomley 42821fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!IS_ERR(ecomp) && addl_desc_ptr) 42921fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_process_descriptor(ecomp, 43021fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr); 43121fab1d0595eacf781705ec3509012a28f298245James Bottomley } 43221fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) 43321fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len; 43421fab1d0595eacf781705ec3509012a28f298245James Bottomley 43521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (addl_desc_ptr) 43621fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr += addl_desc_ptr[1] + 2; 43721fab1d0595eacf781705ec3509012a28f298245James Bottomley 43821fab1d0595eacf781705ec3509012a28f298245James Bottomley } 43921fab1d0595eacf781705ec3509012a28f298245James Bottomley } 44021fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 44121fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(hdr_buf); 44221fab1d0595eacf781705ec3509012a28f298245James Bottomley} 44321fab1d0595eacf781705ec3509012a28f298245James Bottomley 4449927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_match_to_enclosure(struct enclosure_device *edev, 4459927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev) 4469927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 44740c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox unsigned char *buf; 4489927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 44940c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox unsigned int vpd_len; 4509927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd efd = { 4519927c68864e9c39cc317b4f559309ba29e642168James Bottomley .addr = 0, 4529927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 4539927c68864e9c39cc317b4f559309ba29e642168James Bottomley 454e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 455e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE)) 456e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley goto free; 4579927c68864e9c39cc317b4f559309ba29e642168James Bottomley 45821fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); 45921fab1d0595eacf781705ec3509012a28f298245James Bottomley 46040c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox vpd_len = ((buf[2] << 8) | buf[3]) + 4; 461e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley kfree(buf); 462e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley buf = kmalloc(vpd_len, GFP_KERNEL); 463e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len)) 464e3deec090558d5cb5ffdc574e5560f3ed9723394James Bottomley goto free; 465671a99c8eb2f1dde08ac5538d8cd912047c61ddfJames Bottomley 4669927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = buf + 4; 467671a99c8eb2f1dde08ac5538d8cd912047c61ddfJames Bottomley while (desc < buf + vpd_len) { 4689927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] >> 4; 4699927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 code_set = desc[0] & 0x0f; 4709927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 piv = desc[1] & 0x80; 4719927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 assoc = (desc[1] & 0x30) >> 4; 4729927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 type = desc[1] & 0x0f; 4739927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 len = desc[3]; 4749927c68864e9c39cc317b4f559309ba29e642168James Bottomley 475b3f1f9aa082b2ab86dec4db3d8b1566af345387eRoel Kluin if (piv && code_set == 1 && assoc == 1 4769927c68864e9c39cc317b4f559309ba29e642168James Bottomley && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) 4779927c68864e9c39cc317b4f559309ba29e642168James Bottomley efd.addr = (u64)desc[4] << 56 | 4789927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[5] << 48 | 4799927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[6] << 40 | 4809927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[7] << 32 | 4819927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[8] << 24 | 4829927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[9] << 16 | 4839927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[10] << 8 | 4849927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[11]; 4859927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4869927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc += len + 4; 4879927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 4889927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!efd.addr) 4899927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto free; 4909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4919927c68864e9c39cc317b4f559309ba29e642168James Bottomley efd.dev = &sdev->sdev_gendev; 4929927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4939927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); 4949927c68864e9c39cc317b4f559309ba29e642168James Bottomley free: 4959927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(buf); 4969927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 4979927c68864e9c39cc317b4f559309ba29e642168James Bottomley 498ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic int ses_intf_add(struct device *cdev, 4999927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct class_interface *intf) 5009927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 501ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(cdev->parent); 5029927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *tmp_sdev; 50321fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *hdr_buf, *type_ptr; 5049927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 5059927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 50621fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, types, len, components = 0; 5079927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENOMEM; 5088c3adc796f32fa4878ec843f8960717ba377e024James Bottomley int num_enclosures; 5099927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 5107c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu struct ses_component *scomp = NULL; 5119927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5129927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scsi_device_enclosure(sdev)) { 5139927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* not an enclosure, but might be in one */ 514163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley struct enclosure_device *prev = NULL; 515163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley 516163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 5179927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, sdev); 518163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley prev = edev; 5199927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5209927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -ENODEV; 5219927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5229927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5239927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* TYPE_ENCLOSURE prints a message in probe */ 5249927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 5259927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); 5269927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5279927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); 5289927c68864e9c39cc317b4f559309ba29e642168James Bottomley hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 5299927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!hdr_buf || !ses_dev) 5309927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_init_free; 5319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5329927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); 5339927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5349927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5359927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5369927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5379927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5389927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5399927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5409927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5419927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, buf, len); 5429927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5439927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5449927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5458c3adc796f32fa4878ec843f8960717ba377e024James Bottomley types = 0; 5469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5478c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* we always have one main enclosure and the rest are referred 5488c3adc796f32fa4878ec843f8960717ba377e024James Bottomley * to as secondary subenclosures */ 5498c3adc796f32fa4878ec843f8960717ba377e024James Bottomley num_enclosures = buf[1] + 1; 5509927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5518c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* begin at the enclosure descriptor */ 5528c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr = buf + 8; 5538c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* skip all the enclosure descriptors */ 5548c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) { 5558c3adc796f32fa4878ec843f8960717ba377e024James Bottomley types += type_ptr[2]; 5568c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr += type_ptr[3] + 4; 5578c3adc796f32fa4878ec843f8960717ba377e024James Bottomley } 5588c3adc796f32fa4878ec843f8960717ba377e024James Bottomley 5598c3adc796f32fa4878ec843f8960717ba377e024James Bottomley ses_dev->page1_types = type_ptr; 5608c3adc796f32fa4878ec843f8960717ba377e024James Bottomley ses_dev->page1_num_types = types; 5618c3adc796f32fa4878ec843f8960717ba377e024James Bottomley 5628c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) { 5639927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 5649927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) 5659927c68864e9c39cc317b4f559309ba29e642168James Bottomley components += type_ptr[1]; 5669927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5677c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1 = buf; 5687c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1_len = len; 5697c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5709927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5719927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); 5729927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5739927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5749927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5759927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5769927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5779927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5789927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5799927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5809927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* make sure getting page 2 actually works */ 5819927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, buf, len); 5829927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5839927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5849927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2 = buf; 5859927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2_len = len; 5867c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5879927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5889927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* The additional information page --- allows us 5899927c68864e9c39cc317b4f559309ba29e642168James Bottomley * to match up the devices */ 5909927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); 591691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!result) { 592691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 593691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 594691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = kzalloc(len, GFP_KERNEL); 595691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!buf) 596691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto err_free; 597691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 598691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu result = ses_recv_diag(sdev, 10, buf, len); 599691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (result) 600691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto recv_failed; 601691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10 = buf; 602691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10_len = len; 603691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = NULL; 604691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu } 6057c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); 6069927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scomp) 6077c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu goto err_free; 6089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 60971610f55fa4db63dbf5385929a47c9fb2451f332Kay Sievers edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), 6109927c68864e9c39cc317b4f559309ba29e642168James Bottomley components, &ses_enclosure_callbacks); 6119927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (IS_ERR(edev)) { 6129927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = PTR_ERR(edev); 6139927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 6149927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6159927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6169b3a6549b2602ca30f58715a0071e29f9898cae9Julia Lawall kfree(hdr_buf); 6179b3a6549b2602ca30f58715a0071e29f9898cae9Julia Lawall 6189927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = ses_dev; 6199927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < components; i++) 6207c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu edev->component[i].scratch = scomp + i; 6219927c68864e9c39cc317b4f559309ba29e642168James Bottomley 62221fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, sdev, 1); 6239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6249927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* see if there are any devices matching before 6259927c68864e9c39cc317b4f559309ba29e642168James Bottomley * we found the enclosure */ 6269927c68864e9c39cc317b4f559309ba29e642168James Bottomley shost_for_each_device(tmp_sdev, sdev->host) { 6279927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) 6289927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 6299927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, tmp_sdev); 6309927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6329927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6339927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6349927c68864e9c39cc317b4f559309ba29e642168James Bottomley recv_failed: 6359927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", 6369927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 6379927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = -ENODEV; 6389927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_free: 6399927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(buf); 6407c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(scomp); 6419927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page10); 6429927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6439927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6449927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_init_free: 6459927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6469927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(hdr_buf); 6479927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); 6489927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 6499927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6509927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6519927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_remove(struct device *dev) 6529927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6539927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6549927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6559927c68864e9c39cc317b4f559309ba29e642168James Bottomley 65643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_component(struct scsi_device *sdev) 65743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 65843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct enclosure_device *edev, *prev = NULL; 65943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 66043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 66143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley prev = edev; 66243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) 66343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley break; 66443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley } 66543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (edev) 66643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley put_device(&edev->edev); 66743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 66843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 66943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_enclosure(struct scsi_device *sdev) 6709927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6719927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 6729927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 6739927c68864e9c39cc317b4f559309ba29e642168James Bottomley 674163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley /* exact match to this enclosure */ 67543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley edev = enclosure_find(&sdev->sdev_gendev, NULL); 6769927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev) 6779927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 6789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6799927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = edev->scratch; 6809927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = NULL; 6819927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6827c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(ses_dev->page10); 6839927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6849927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6859927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6869927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6879927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(edev->component[0].scratch); 6889927c68864e9c39cc317b4f559309ba29e642168James Bottomley 689ee959b00c335d7780136c5abda37809191fe52c3Tony Jones put_device(&edev->edev); 6909927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_unregister(edev); 6919927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6929927c68864e9c39cc317b4f559309ba29e642168James Bottomley 69343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove(struct device *cdev, 69443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct class_interface *intf) 69543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 69643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct scsi_device *sdev = to_scsi_device(cdev->parent); 69743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 69843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!scsi_device_enclosure(sdev)) 69943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_component(sdev); 70043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley else 70143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_enclosure(sdev); 70243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 70343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 7049927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct class_interface ses_interface = { 705ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .add_dev = ses_intf_add, 706ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .remove_dev = ses_intf_remove, 7079927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 7089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7099927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct scsi_driver ses_template = { 7109927c68864e9c39cc317b4f559309ba29e642168James Bottomley .owner = THIS_MODULE, 7119927c68864e9c39cc317b4f559309ba29e642168James Bottomley .gendrv = { 7129927c68864e9c39cc317b4f559309ba29e642168James Bottomley .name = "ses", 7139927c68864e9c39cc317b4f559309ba29e642168James Bottomley .probe = ses_probe, 7149927c68864e9c39cc317b4f559309ba29e642168James Bottomley .remove = ses_remove, 7159927c68864e9c39cc317b4f559309ba29e642168James Bottomley }, 7169927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 7179927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7189927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int __init ses_init(void) 7199927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7209927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err; 7219927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7229927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_interface(&ses_interface); 7239927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7249927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7259927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7269927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_driver(&ses_template.gendrv); 7279927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7289927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out_unreg; 7299927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7309927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 7319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7329927c68864e9c39cc317b4f559309ba29e642168James Bottomley out_unreg: 7339927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7349927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7359927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7379927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void __exit ses_exit(void) 7389927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7399927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_driver(&ses_template.gendrv); 7409927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7419927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7429927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7439927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_init(ses_init); 7449927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_exit(ses_exit); 7459927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7469927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); 7479927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7489927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_AUTHOR("James Bottomley"); 7499927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); 7509927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_LICENSE("GPL v2"); 751